cs224n作业 神经网络前向传播后向传播

原来只是自己没有往后看,后面视频解释了前向和后向传播。

前向传播网络

一个简单的网络:

前向传播会更新权重参数吗 前向传播和后向传播_后向传播


我看不懂这个红点图,同层神经元组与组之间的空格意味着什么?希望有大神赐教一下

后向传播网络

对于后向传播网络,从视频里的多种方式,我觉得最好理解的还是FLOW CHART,就是后向传播的时候,像流水一样一层一层的往后走。

核心:后向的时候记录下每一层的梯度,然后不断往后流动

前向传播会更新权重参数吗 前向传播和后向传播_神经网络推导_02


前向传播会更新权重参数吗 前向传播和后向传播_反向传播_03

  看完(前两讲)视频做这个作业的时候,可卡住我好一会,这里特此记录一下。其实神经网络前向后向推导不难,难就在于网上很多教程没有把特征和维数讲清楚,以致于在具体写代码实现的过程中卡壳,同样也反映了自己目前思考问题还是平面,没有达到空间思考的程度。
   其实首先不是去思考前向传播时什么,后向传播是什么,首先应该思考这每一层的维数,即shape是什么 。

基本定义:
激活函数:第一层为sigmod,第二层为softmax
n:样本数量
前向传播会更新权重参数吗 前向传播和后向传播_前向传播会更新权重参数吗_04:第一层的特征数
H:第二层的特征数
前向传播会更新权重参数吗 前向传播和后向传播_神经网络推导_05:第三层的特征数
前向传播会更新权重参数吗 前向传播和后向传播_神经网络_06

很明显,下图就存在这样的维度转化:

前向传播会更新权重参数吗 前向传播和后向传播_后向传播_07

前向传播会更新权重参数吗 前向传播和后向传播_神经网络推导_08


知道了具体的维度,然后我们来推前向和后向传播的公式

前向传播很容易理解,就是按照公式得到下一层结果,不需要求导什么的复杂公式。这里我们定义第一层是sigmod函数,第二层是softmax函数。

前向传播

前向传播会更新权重参数吗 前向传播和后向传播_神经网络推导_09

反向传播

反向传播实际上就是一系列的链式求导法则,这里有一些常识需要补充一下

前向传播会更新权重参数吗 前向传播和后向传播_反向传播_10:通常是代指整个公式中涉及到的所有参数的代名词,并不是指公式中真的需要有一个参数叫前向传播会更新权重参数吗 前向传播和后向传播_反向传播_10,比如说这里的W,b(代码里他们是放到一个数组里面,需要的时候再按需取不同位置的参数)
交叉熵函数:为什么使用交叉熵函数是有一番讲究的,我了解到的,一个是求导后的形式好用,另一个是求导后的导数比单纯L2变化更快。具体可以参考

这里反向传播没有用上正则项,后面用上了再补。
定义损失函数:
前向传播会更新权重参数吗 前向传播和后向传播_后向传播_12
注意i是样本数,j是具体的特征维数,理解清楚这里的下标非常重要
我们先关注内层的求和公式,即交叉熵函数(因为外层的求和跟我们求导的参数其实无关,只是对各个样本求导后的平均值)
自己踩的一坑就是没有把形式写清楚就取摸索求导过程了,一开始应该先把形式过程写清楚
推导第二层:
前向传播会更新权重参数吗 前向传播和后向传播_反向传播_13
推导第一层(形式是类似的),为什么叫反向传播,就是每一层推导都保存了$ \frac{\partial J}{\partial h$,方便下一层的推导
前向传播会更新权重参数吗 前向传播和后向传播_反向传播_14

具体函数求导的过程这里不详细展开,主要说明一下,关于交叉熵函数的求导
前向传播会更新权重参数吗 前向传播和后向传播_后向传播_15
这里的i和j都是指特征维数,这就导致对第k维进行求导的时候,会存在两种形式,一个可以忽略softmax的分子,一个不可以忽略
前向传播会更新权重参数吗 前向传播和后向传播_后向传播_16
前向传播会更新权重参数吗 前向传播和后向传播_反向传播_17
这里的i是指针对某一维的参数进行求导。
具体其他函数的求导过程可以百度,以下给出代码形式:

# 变量还是要写清楚维度,不然写代码的时候很容然忘记转置
#前向传播
    layer1=np.dot(data,W1)+b1
    layer1_a=sigmoid(layer1)
    layer2=np.dot(layer1_a,W2)+b2
    probs=softmax(layer2)
#后向传播
    cost = -np.sum(np.sum(labels*np.log(probs),axis=1)) /N
    #这里要注意矩阵乘法的时候就把n个样本的值加再一起了,所以不需要sum直接除N
    gradW2=np.dot(layer1_a.T,probs-labels)/N
    #这里要注意sum,因为损失函数还有外层对每个样本求导后的平均值
    gradb2=np.sum((probs-labels),axis=0)/N
    # 记录下当前层的导数,便于下一层计算
    dlayer2=np.dot(probs-labels,W2.T)/N

    dlayer1 = (1-layer1_a)*layer1_a*dlayer2
    gradW1 = np.dot(data.T, dlayer1)
    gradb1 = np.sum(dlayer1,axis =0)