这是俺研究生阶段的一次作业题,俺通过这道题加深了对于神经网络反向传播的理解。
首先:
import numpy as np
显然输入和输出矩阵是这样的:
Input = np.array([1,3,1]) //x1和x2直接代入
y1 = 0.9
y2 = 0.3
Output = np.array([y1,y2])
根据初始的权重矩阵,定义连接输入层和隐藏层的核kernel1以及连接隐藏层和输出层的核kerne2:
kernel1 = np.array([[1,2],[-2,0],[3,-1]],dtype=np.float64)
kernel2 = np.array([[1,1],[0,-2],[-2,3]],dtype=np.float64)
A.定义向前传播的过程:
1.输入的数据input与kernel1进行矩阵乘法后输入到第一层神经元中hidden_inputs;
2.经过sigmoid激励函数所输出的两个值加上-1(一共三个元素)构成了对于输出层的输入np.append(hidden_outputs,-1);
3.np.append(hidden_outputs,-1)与kernel2进行矩阵乘法之后输入到输出层的神经元中;
4.最后经过sigmoid函数输出final_outputs。
#前向传播
hidden_inputs = np.dot(inputs, kernel1)
hidden_outputs = sigmoid(hidden_inputs)
final_inputs = np.dot(np.append(hidden_outputs,-1),kernel2)
final_outputs= sigmoid(final_inputs)
B.此时可计算实际的输出和期待的输出之间的误差,以此来指导优化过程以及避免过拟合:
#计算误差
def calculate_error(except_y, y):
return 0.5 * np.sum((except_y - y)**2)
#误差计算
error = calculate_error(final_outputs, expect_output)
C.反向传播的过程:
1.计算了输出层的误差output_errors,即期望输出和实际输出之间的差异;
2.计算输出层的误差项,使用了输出层的激活函数的导数(这里使用了 sigmoid 激励函数)。这个误差项会用于调整输出层的权重;
3.接着计算隐藏层的误差hidden_error,即通过将输出层的误差项与连接隐藏层和输出层的权重矩阵相乘得到;
4.计算隐藏层的误差项,同样使用了隐藏层的激活函数的导数。这个误差项会用于调整隐藏层的权重。不过要注意-1不是隐藏层的输出,而是临时加进来的量,所以隐藏层的误差最后一个元素要剔除。
#反向传播
output_errors = expect_output - final_outputs
output_delta = output_errors * sigmoid_derivative(final_outputs)
hidden_errors = np.dot(kernel2, output_delta)
hidden_delta = hidden_errors[:-1] * sigmoid_derivative(hidden_outputs)
#更新参数
kernel2 += lr * np.outer(np.append(hidden_outputs, -1), output_delta)
kernel1 += lr * np.outer(inputs, hidden_delta)
D.最后更新参数,整个训练过程结束:
通过梯度下降的方法更新参数。
#更新参数
kernel2 += lr * np.outer(np.append(hidden_outputs, -1), output_delta)
kernel1 += lr * np.outer(inputs, hidden_delta)
E.训练过程:
for epoch in range(12000):
final_outputs,expect_output, error = forward_and_backward(Input, kernel1, kernel2, Output, lr = 0.05)
if epoch % 1000 == 0:
print(f"Epoch {epoch+1000}, Error: {np.mean(np.abs(expect_output - final_outputs))}")
D.训练结果: