从零开始搭建神经网络(三)含隐藏层的神经网络
单层感知机的学习能力有限,对于非线性可分的情况下分类效果不好,因此为了让网络拥有更强大的学习能力,需要在输入和输出层之间添加隐藏层。
下面实现一个简单含隐藏层的神经网络结构,是一个二分问题,输入为两维,输出为两类。
1.**函数
由于添加了隐藏层,因此**函数分为隐藏层的**函数和输出层的**函数,这里隐藏层的**函数使用tanh()**函数,输出层还是使用sigmoid()**函数,这里使用上一篇的代码,至于tanh()**函数到时候使用np.tanh()就行了
def sigmoid(z):
"""
sigmoid**函数
:param z: 输入
:return: sigmoid(z)
"""
return 1/(1 + np.exp(-z))
2.初始化参数
初始化参数和不含隐藏层的升级网络没有多大区别,只是要初始化的参数多了一些而已,权重采用随机初始化,偏置零值初始化。这里需要讲一下各变量初始化的维度。以我们的图为例, 当处于在隐藏层这一层时,输入维度为(2,1),输出维度为(3,1),根据矩阵乘法公式和**函数输出,可以得到权重矩阵W的维度为(3,2),如下图所示。偏置的维度同理。
def initialize_parameters(in_n, h_n, out_n):
"""
初始化权重和偏置
in_n -- 输入层节点数
h_n -- 隐藏层节点数
out_n -- 输出层结点数
returns:
params --
W1 -- 权重矩阵,维度为(h_n, in_n)
b1 -- 偏置向量,维度为(h_n, 1)
W2 -- 权重矩阵,维度为 (out_n, h_n)
b2 -- 偏置向量,维度为 (out_n, 1)
"""
W1 = np.random.randn(h_n, in_n) * 0.01
b1 = np.zeros((h_n, 1))
W2 = np.random.randn(out_n, h_n) * 0.01
b2 = np.zeros((out_n, 1))
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
3.BP算法
含隐藏层的神经网络的BP算法要复杂一些因为要一层一层的正向传播,然后再反向传播回来。下面讲一下含隐藏层的BP算法。前向传播和不含隐藏层的神经网络一样,从输入层开始依次计算每一层的输入,上一次的输出当做当前层的输入;反向传播则是从输出层开始依次进行梯度下降,公式就不进行具体的推导了,在下面直接给出,可以参考:从零开始搭建神经网络(二)数学公式及代码实现。因为含隐藏层的BP算法比较复杂,所以前向传播和反向传播分开来写,
def forward_propagation(X, parameters):
"""
前向传播
X -- 输入数据
parameters -- 参数(包含W1,b1,W2,b2)
returns:
A2 -- 网络输出
temp -- 包含 Z1, A1, Z2,A2的字典,用于BP算法
"""
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
Z1 = np.dot(W1, X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2)
temp = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
return A2,temp
def backward_propagation(parameters, temp, X, Y):
"""
反向传播
parameters -- 参数(包含W1,b1,W2,b2)
temp -- 包含 Z1, A1, Z2,A2的字典,用于BP算法
X -- 输入数据
Y -- 输入数据标签
returns:
grads -- 返回不同参数的梯度
cost -- 损失函数
"""
# 取回参数
W1 = parameters["W1"]
W2 = parameters["W2"]
A1 = temp["A1"]
A2 = temp["A2"]
# 样本数目
num = Y.shape[0]
# 交叉熵损失函数
cost = -1 / num * np.sum(Y * np.log(A2) + (1 - Y) * np.log(1 - A2))
# 反向传播
dZ2 = A2 - Y
dW2 = 1 / num * np.dot(dZ2, A1.T)
db2 = 1 / num * np.sum(dZ2, axis=1, keepdims=True)
dZ1 = np.dot(W2.T, dZ2) * (1 - np.power(A1, 2))
dW1 = 1 / num * np.dot(dZ1, X.T)
db1 = 1 / num * np.sum(dZ1, axis=1, keepdims=True)
gradients = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return cost,gradients
4.参数更新
参数更新和其他的完全一样,不懂的参考我上一篇博客。
def update_parameters(parameters, gradients, learning_rate):
"""
梯度下降法更新参数
parameters -- 参数(包含W1,b1,W2,b2)
grads -- 不同参数的梯度
returns:
parameters -- 更新后的参数
"""
#取回参数
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
dW1 = gradients["dW1"]
db1 = gradients["db1"]
dW2 = gradients["dW2"]
db2 = gradients["db2"]
# 更新参数
W1 -= learning_rate * dW1
b1 -= learning_rate * db1
W2 -= learning_rate * dW2
b2 -= learning_rate * db2
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
5.预测
根据神经网络的输出值来进行预测,公式如下:
def predict(parameters, X):
"""
使用学习好的参数来预测
parameters -- 学习好的参数
X -- 输入数据
Returns
predictions -- 预测结果0/1
"""
A2, temp = forward_propagation(X, parameters)
predictions = np.round(A2)
return predictions
6. 完整实例
下图是中的两类点是线性不可分的,利用这些数据测试下含隐藏层的神经网络的学习能力
if __name__ == "__main__":
# X为横坐标,Y为纵坐标
X = [0, 0, 1, 1]
Y = [0, 1, 0, 1]
label = [1, 0, 0, 1]
# 第一类为蓝色,第二类为红色
label_color = ['blue', 'red']
color = []
for i in label:
if i == 1:
color.append(label_color[0])
else:
color.append(label_color[1])
# 数据归一化
X = np.array(X)
Y = np.array(Y)
X = (X - np.average(X))
Y = (Y - np.average(Y))
X = X / X.max()
Y = Y / Y.max()
for i in range(len(X)):
plt.scatter(X[i], Y[i], c=color[i])
plt.title('Normalization Data')
plt.show()
data_X = np.vstack((X, Y))
data_label = np.array([label])
# 参数设置
in_n = 2
h_n = 3
out_n = 1
costs = []
Y_prediction = []
iters = 2000
learning_rate = 2
parameters = initialize_parameters(in_n, h_n, out_n)
#开始训练
for i in range(iters):
# 前向传播
A2, temp = forward_propagation(data_X, parameters)
# 反向传播
costTemp, gradients = backward_propagation(parameters, temp, data_X, data_label)
costs.append(costTemp)
# 参数更新
parameters = update_parameters(parameters, gradients, learning_rate)
# 预测
Y_prediction = predict(parameters, data_X)
plot_decision_boundary(lambda x: predict(parameters, x.T), data_X, data_label)
plt.show()
# #画图
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
分类结果如下图所示,可以发现含隐藏层的神经网络可以对线性不可分的数据进行分类
上一篇: 多层感知器(神经网络)与**函数
下一篇: 基于卷积神经网络的目标检测算法
推荐阅读
-
从零开始搭建神经网络(三)含隐藏层的神经网络
-
Python实现的三层BP神经网络算法示例
-
TF之DNN:TF利用简单7个神经元的三层全连接神经网络实现降低损失到0.000以下(输入、隐藏、输出层分别为 2、3 、 2 个神经元)——Jason niu
-
Python实现一个简单三层神经网络的搭建及测试 代码解析
-
Python实现的三层BP神经网络算法示例
-
用js实现一个三层的bp神经网络
-
吴恩达作业8:三层神经网络实现手势数字的识别(基于tensorflow)
-
三步教你搭建给黑白照片上色的神经网络 !(附代码)
-
利用BP神经网络 设计一个三层神经网络解决手写数字的识别问题
-
使用python搭建单隐藏层神经网络用于分类