首先,这是一张本节的神经网络懵逼图全貌图!
可以看出,这图显示的元素非常乱七八糟丰富。我会逐个字母逐个数字的告诉你这是什么,那是什么。
等我说完了,以及你知道这些字母是什么的时候,我们将一起实现它。
第0层:这是输入层,1代表偏置神经元。x是输入,而且它们都被按照顺序编了号。
第0层与第1层之间:w是权重,括号里的1代表当前层数。
w右下角的11代表右边层的第1个神经元与左边层的第1个神经元。
w右下角的12代表右边层的第1个神经元与左边层的第2个神经元。
为什么左边的数字代表右边的神经元序号,而右边的数字反而代表左边的神经元序号呢?
因为权重与右边的层才是一对。这一对构成一层网络。w当然先把主子的序号放前面。
那如果序列超过9怎么表示呢?
这些表示方法只在本节有效,老夫保证不会超过9的。
第1层:a就是输出x*权重w+偏置b,括号的数字是当前层,右下角是序号。h是激活函数。z是激活函数返回的结果。
后面几层的工作也是大同小异。
注意,最后一层,输出层的激活函数与隐藏层的有些不同。用σ表示的。稍微我会提到这个函数的不同。
为了实现这个神经网络,下面先打一个草稿:
准备工作:
1.准备好所需的函数工具:隐藏层激活函数,输出层激活函数,矩阵乘积函数
2.得到每一层的偏置和权重。
第一层:
3.得到a1:输入数据及第1层权重的积乘+第1层偏置
4.得到z1:把a1带入激活函数,返回z1
第二层:
5.得到a2:z1及第2层权重的积乘+第2层偏置
6.得到z2:把a2带入激活函数,返回z2
第三层:
7.得到a3:z2及第3层权重的积乘+第3层偏置
8.得到z3:把a3带入激活函数,返回z3
接下来逐步的实现这些
第1步:准备好所需的激活函数
#隐藏层激活函数
def sigmoid_function(x):
return 1/(1+np.exp(-x))
#输出层激活函数
def identity_function(x):
return x
#矩阵乘积函数
def mattrix_dot(A,B):
return np.dot(A,B)
第2步.得到每一层的偏置和权重。
#得到偏置量和权重
def get_init_data():
# 第0层偏置量
b1=np.array([0.1,0.2,0.3])
# 第1层偏置量
b2=np.array([0.1,0.2])
# 第2层偏置量
b3=np.array([0.1,0.2])
# 第1层权重
W1=np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
# 第2层权重
W2=np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
# 第3层权重
W3=np.array([[0.1, 0.3], [0.2, 0.4]])
return b1,b2,b3,W1,W2,W3
这些数据都是我们自己乱编的,所以这个神经网络暂时还做不了什么神奇的事情。
下面在main主函数里,实现三层网络需要做的事
def main():
b1, b2,b3, W1, W2, W3=get_init_data()
#输入层数据
x1,x2=[1.0, 0.5]
x=np.array([x1,x2])
#第1层
a1=mattrix_dot(x, W1)+b1 # 第3步:得到a1:输入数据及第1层权重的积乘+第1层偏置
z1=sigmoid_function(a1) # 第4步:得到z1:把a1带入激活函数,返回z1
#第2层
a2=mattrix_dot(z1, W2)+b2 # 第3步:得到a2:z1及第2层权重的积乘+第2层偏置
z2=sigmoid_function(a2) # 第4步:得到z2:把a2带入激活函数,返回z2
#第3层
a3=mattrix_dot(z2, W3)+b3 # 第3步:得到a3:z2及第3层权重的积乘+第3层偏置
z3=identity_function(a3) # 第4步:得到z3:把a3带入激活函数,返回z3
print(z3) #输出[0.31682708 0.69627909]
可以看到。实现这个复杂的神经网络,代码却并不复杂。这得益于numpy模块带来的便捷。
另外值得吐槽的是,输出层的激活函数identity_function()太'精简'了。
即便这样,人家也有个好听的名字---'恒等函数'。
恒等函数会将输入按原样输出,对于输入的信息,不加以任何改动地直接输出。
输出层通常根据其用途选择不同的激活函数。
在 回归问题上,通常选择恒等函数,在分类问题上,通常选择softmax()函数。
下一节《输出层的设计》会提到softmax()函数。
--------结语--------
午餐吃什么呢?
汉堡+可乐不错。