|
|
@@ -23,12 +23,12 @@ |
|
|
|
"\n", |
|
|
|
"计算一个神经元的输出的方法和计算一个感知器的输出是一样的。假设神经元的输入是向量$\\vec{x}$,权重向量是$\\vec{w}$(偏置项是$w_0$),激活函数是sigmoid函数,则其输出$y$:\n", |
|
|
|
"$$\n", |
|
|
|
"y = sigmod(\\vec{w}^T \\cdot \\vec{x})\n", |
|
|
|
"y = sigmoid(\\vec{w}^T \\cdot \\vec{x})\n", |
|
|
|
"$$\n", |
|
|
|
"\n", |
|
|
|
"sigmoid函数的定义如下:\n", |
|
|
|
"$$\n", |
|
|
|
"sigmod(x) = \\frac{1}{1+e^{-x}}\n", |
|
|
|
"sigmoid(x) = \\frac{1}{1+e^{-x}}\n", |
|
|
|
"$$\n", |
|
|
|
"将其带入前面的式子,得到\n", |
|
|
|
"$$\n", |
|
|
@@ -57,11 +57,11 @@ |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"神经网络就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(Full Connected, FC)神经网络,通过观察上面的图,我们可以发现它的规则包括:\n", |
|
|
|
"神经网络就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(Full Connected, FC)神经网络,通过观察上面的图,可以发现它的规则包括:\n", |
|
|
|
"\n", |
|
|
|
"* 神经元按照层来布局\n", |
|
|
|
" - 最左边的层叫做输入层,负责接收输入数据;\n", |
|
|
|
" - 最右边的层叫输出层,我们可以从这层获取神经网络输出数据;\n", |
|
|
|
" - 最右边的层叫输出层,可以从这层获取神经网络输出数据;\n", |
|
|
|
" - 输入层和输出层之间的层叫做隐藏层,因为它们对于外部来说是不可见的。\n", |
|
|
|
"* 同一层的神经元之间没有连接\n", |
|
|
|
"* 第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入\n", |
|
|
@@ -105,7 +105,7 @@ |
|
|
|
"* 隐藏层的4个节点,编号依次为4、5、6、7;\n", |
|
|
|
"* 最后输出层的两个节点编号为8、9。\n", |
|
|
|
"\n", |
|
|
|
"因为我们这个神经网络是全连接网络,所以可以看到每个节点都和上一层的所有节点有连接。比如,我们可以看到隐藏层的节点4,它和输入层的三个节点1、2、3之间都有连接,其连接上的权重分别为$w_{41}$,$w_{42}$,$w_{43}$。那么,我们怎样计算节点4的输出值$a_4$呢?\n" |
|
|
|
"因为这个神经网络是全连接网络,所以可以看到每个节点都和上一层的所有节点有连接。比如,隐藏层的节点4,它和输入层的三个节点1、2、3之间都有连接,其连接上的权重分别为$w_{41}$,$w_{42}$,$w_{43}$。那么,怎样计算节点4的输出值$a_4$呢?\n" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
@@ -113,24 +113,24 @@ |
|
|
|
"metadata": {}, |
|
|
|
"source": [ |
|
|
|
"\n", |
|
|
|
"为了计算节点4的输出值,我们必须先得到其所有上游节点(也就是节点1、2、3)的输出值。节点1、2、3是输入层的节点,所以,他们的输出值就是输入向量$\\vec{x}$本身。按照上图画出的对应关系,可以看到节点1、2、3的输出值分别是$x_1$,$x_2$,$x_3$。我们要求输入向量的维度和输入层神经元个数相同,而输入向量的某个元素对应到哪个输入节点是可以自由决定的。\n", |
|
|
|
"为了计算节点4的输出值,必须先得到其所有上游节点(也就是节点1、2、3)的输出值。节点1、2、3是输入层的节点,所以,他们的输出值就是输入向量$\\vec{x}$本身。按照上图画出的对应关系,可以看到节点1、2、3的输出值分别是$x_1$,$x_2$,$x_3$。要求输入向量的维度和输入层神经元个数相同,而输入向量的某个元素对应到哪个输入节点是可以自由决定的。\n", |
|
|
|
"\n", |
|
|
|
"一旦我们有了节点1、2、3的输出值,我们就可以根据式1计算节点4的输出值$a_4$:\n", |
|
|
|
"一旦有了节点1、2、3的输出值,就可以根据式1计算节点4的输出值$a_4$:\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"上式的$w_{4b}$是节点4的偏置项,图中没有画出来。而$w_{41}$,$w_{42}$,$w_{43}$分别为节点1、2、3到节点4连接的权重,在给权重$w_{ji}$编号时,我们把目标节点的编号$j$放在前面,把源节点的编号$i$放在后面。\n" |
|
|
|
"上式的$w_{4b}$是节点4的偏置项,图中没有画出来。而$w_{41}$,$w_{42}$,$w_{43}$分别为节点1、2、3到节点4连接的权重,在给权重$w_{ji}$编号时,目标节点的编号$j$放在前面,把源节点的编号$i$放在后面。\n" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"cell_type": "markdown", |
|
|
|
"metadata": {}, |
|
|
|
"source": [ |
|
|
|
"同样,我们可以继续计算出节点5、6、7的输出值$a_5$,$a_6$,$a_7$。这样,隐藏层的4个节点的输出值就计算完成了,我们就可以接着计算输出层的节点8的输出值$y_1$:\n", |
|
|
|
"同样,可以继续计算出节点5、6、7的输出值$a_5$,$a_6$,$a_7$。这样,隐藏层的4个节点的输出值就计算完成了,就可以接着计算输出层的节点8的输出值$y_1$:\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"同理,我们还可以计算出$y_2$的值。这样输出层所有节点的输出值计算完毕,我们就得到了在输入向量$\\vec{x} = (x_1, x_2, x_3)^T$时,神经网络的输出向量$\\vec{y} = (y_1, y_2)^T$。这里我们也看到,输出向量的维度和输出层神经元个数相同。\n" |
|
|
|
"同理,我们还可以计算出$y_2$的值。这样输出层所有节点的输出值计算完毕,就得到了在输入向量$\\vec{x} = (x_1, x_2, x_3)^T$时,神经网络的输出向量$\\vec{y} = (y_1, y_2)^T$。可以看出:输出向量的维度和输出层神经元个数相同。\n" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
@@ -141,7 +141,7 @@ |
|
|
|
"\n", |
|
|
|
"神经网络的计算如果用矩阵来表示会很方便,此外可以用优化加速算法提高计算速度。\n", |
|
|
|
"\n", |
|
|
|
"我们先来看看隐藏层的矩阵表示,隐藏层4个节点的计算依次排列出来:\n", |
|
|
|
"隐藏层4个节点的计算依次排列出来:\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
@@ -153,7 +153,7 @@ |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"现在,我们把上述计算$a_4$, $a_5$,$a_6$,$a_7$的四个式子写到一个矩阵里面,每个式子作为矩阵的一行,就可以利用矩阵来表示它们的计算了。令\n", |
|
|
|
"现在,把上述计算$a_4$, $a_5$,$a_6$,$a_7$的四个式子写到一个矩阵里面,每个式子作为矩阵的一行,就可以利用矩阵来表示它们的计算了。令\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
@@ -311,13 +311,13 @@ |
|
|
|
"source": [ |
|
|
|
"### 5.3 具体解释\n", |
|
|
|
"\n", |
|
|
|
"我们假设每个训练样本为$(\\vec{x}, \\vec{t})$,其中向量$\\vec{x}$是训练样本的特征,而$\\vec{t}$是样本的目标值。\n", |
|
|
|
"假设每个训练样本为$(\\vec{x}, \\vec{t})$,其中向量$\\vec{x}$是训练样本的特征,而$\\vec{t}$是样本的目标值。\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"首先,我们根据上一节介绍的算法,用样本的特征$\\vec{x}$,计算出神经网络中每个隐藏层节点的输出$a_i$,以及输出层每个节点的输出$y_i$。\n", |
|
|
|
"首先,根据上一节介绍的算法,用样本的特征$\\vec{x}$,计算出神经网络中每个隐藏层节点的输出$a_i$,以及输出层每个节点的输出$y_i$。\n", |
|
|
|
"\n", |
|
|
|
"然后,我们按照下面的方法计算出每个节点的误差项$\\delta_i$:\n", |
|
|
|
"然后,按照下面的方法计算出每个节点的误差项$\\delta_i$:\n", |
|
|
|
"\n", |
|
|
|
"* **对于输出层节点$i$**\n", |
|
|
|
"\n", |
|
|
@@ -354,8 +354,7 @@ |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"我们已经介绍了神经网络每个节点误差项的计算和权重更新方法。显然,计算一个节点的误差项,需要先计算每个与其相连的下一层节点的误差项。这就要求误差项的计算顺序必须是从输出层开始,然后反向依次计算每个隐藏层的误差项,直到与输入层相连的那个隐藏层。这就是反向传播算法的名字的含义。当所有节点的误差项计算完毕后,我们就可以根据式5来更新所有的权重。\n", |
|
|
|
"\n" |
|
|
|
"计算一个节点的误差项,需要先计算每个与其相连的下一层节点的误差项,这就要求误差项的计算顺序必须是从输出层开始,然后反向依次计算每个隐藏层的误差项,直到与输入层相连的那个隐藏层,这就是反向传播算法的名字的含义。当所有节点的误差项计算完毕后,就可以根据式5来更新所有的权重。" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
@@ -371,20 +370,20 @@ |
|
|
|
"y = f( w_2 f(w_1 x) )\n", |
|
|
|
"$$\n", |
|
|
|
"\n", |
|
|
|
"如果我们不使用激活函数,那么神经网络的结果就是\n", |
|
|
|
"如果不使用激活函数,那么神经网络的结果就是\n", |
|
|
|
"\n", |
|
|
|
"$$\n", |
|
|
|
"y = w_2 (w_1 x) = (w_2 w_1) x = \\bar{w} x\n", |
|
|
|
"$$\n", |
|
|
|
"\n", |
|
|
|
"可以看到,我们将两层神经网络的参数合在一起,用 $\\bar{w}$ 来表示,两层的神经网络其实就变成了一层神经网络,只不过参数变成了新的 $\\bar{w}$,所以如果不使用激活函数,那么不管多少层的神经网络,$y = w_n \\cdots w_2 w_1 x = \\bar{w} x$,就都变成了单层神经网络,所以在每一层我们都必须使用激活函数。\n" |
|
|
|
"可以看到,将两层神经网络的参数合在一起,用 $\\bar{w}$ 来表示,两层的神经网络其实就变成了一层神经网络,只不过参数变成了新的 $\\bar{w}$,所以如果不使用激活函数,那么不管多少层的神经网络,$y = w_n \\cdots w_2 w_1 x = \\bar{w} x$,就都变成了单层神经网络,所以在每一层都必须使用激活函数。\n" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"cell_type": "markdown", |
|
|
|
"metadata": {}, |
|
|
|
"source": [ |
|
|
|
"最后我们看看激活函数对神经网络的影响\n", |
|
|
|
"最后看看激活函数对神经网络的影响\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
@@ -730,7 +729,7 @@ |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
|
"# define sigmod\n", |
|
|
|
"def sigmod(X):\n", |
|
|
|
"def sigmoid(X):\n", |
|
|
|
" return 1.0/(1+np.exp(-X))\n", |
|
|
|
"\n", |
|
|
|
"\n", |
|
|
@@ -764,7 +763,7 @@ |
|
|
|
" Z = []\n", |
|
|
|
" x0 = X\n", |
|
|
|
" for i in range(len(self.nodes)-1):\n", |
|
|
|
" z = sigmod(np.dot(x0, self.W[i]) + self.B[i])\n", |
|
|
|
" z = sigmoid(np.dot(x0, self.W[i]) + self.B[i])\n", |
|
|
|
" x0 = z\n", |
|
|
|
" \n", |
|
|
|
" Z.append(z)\n", |
|
|
@@ -1011,7 +1010,7 @@ |
|
|
|
], |
|
|
|
"metadata": { |
|
|
|
"kernelspec": { |
|
|
|
"display_name": "Python 3 (ipykernel)", |
|
|
|
"display_name": "Python 3", |
|
|
|
"language": "python", |
|
|
|
"name": "python3" |
|
|
|
}, |
|
|
@@ -1025,7 +1024,7 @@ |
|
|
|
"name": "python", |
|
|
|
"nbconvert_exporter": "python", |
|
|
|
"pygments_lexer": "ipython3", |
|
|
|
"version": "3.9.7" |
|
|
|
"version": "3.7.9" |
|
|
|
} |
|
|
|
}, |
|
|
|
"nbformat": 4, |
|
|
|