从零实现Python深度学习神经网络模型训练,核心是要理解神经网络的前向传播与反向传播逻辑,不依赖TensorFlow、PyTorch等现成框架,手动完成参数更新和模型迭代过程。这种方式能帮助开发者深入理解深度学习的核心原理,避免对框架的过度依赖。
核心概念铺垫
神经网络的基础单元是神经元,每个神经元接收输入后经过加权求和与激活函数处理输出结果。常见的激活函数有Sigmoid、ReLU等,损失函数用于衡量模型预测值与真实值的差距,反向传播则是通过梯度下降更新网络参数的核心方法。
基础工具准备
从零实现不需要复杂依赖,只需要Python内置的math库和列表操作即可,后续为了提升计算效率可以引入numpy,本文先使用纯Python实现基础逻辑。
从零实现神经网络的完整步骤
1. 定义神经元与激活函数
首先实现Sigmoid激活函数及其导数,后续反向传播会用到导数计算:
import math
# 定义Sigmoid激活函数
def sigmoid(x):
return 1 / (1 + math.exp(-x))
# 定义Sigmoid函数的导数,用于反向传播计算梯度
def sigmoid_derivative(x):
return x * (1 - x)
2. 初始化网络参数
假设我们实现一个输入层2个节点、隐藏层2个节点、输出层1个节点的简单神经网络,需要初始化各层的权重和偏置:
# 初始化网络参数,权重使用随机小值,偏置初始化为0
def init_parameters():
# 输入层到隐藏层的权重,2*2矩阵
w1 = [[0.15, 0.20], [0.25, 0.30]]
# 隐藏层偏置
b1 = [0.35, 0.35]
# 隐藏层到输出层的权重,2*1矩阵
w2 = [[0.40], [0.45]]
# 输出层偏置
b2 = [0.6]
return w1, b1, w2, b2
3. 实现前向传播
前向传播是输入数据经过各层计算得到输出结果的过程:
# 前向传播计算
def forward_propagation(input_data, w1, b1, w2, b2):
# 输入层到隐藏层的计算
hidden_layer_input = []
for i in range(len(w1[0])):
sum_val = 0
for j in range(len(input_data)):
sum_val += input_data[j] * w1[j][i]
sum_val += b1[i]
hidden_layer_input.append(sum_val)
# 隐藏层激活
hidden_layer_output = [sigmoid(x) for x in hidden_layer_input]
# 隐藏层到输出层的计算
output_layer_input = 0
for i in range(len(hidden_layer_output)):
output_layer_input += hidden_layer_output[i] * w2[i][0]
output_layer_input += b2[0]
# 输出层激活
output = sigmoid(output_layer_input)
return hidden_layer_output, output
4. 定义损失函数
这里使用均方误差作为损失函数,衡量预测值与真实值的差距:
# 均方误差损失函数
def mse_loss(predict, true_value):
return 0.5 * (predict - true_value) ** 2
# 损失函数导数
def mse_loss_derivative(predict, true_value):
return predict - true_value
5. 实现反向传播与参数更新
反向传播根据损失函数的梯度更新各层权重和偏置,这里使用学习率控制参数更新幅度:
# 反向传播更新参数
def backward_propagation(input_data, hidden_output, final_output, true_value, w1, b1, w2, b2, learning_rate=0.5):
# 计算输出层梯度
output_error = mse_loss_derivative(final_output, true_value)
output_delta = output_error * sigmoid_derivative(final_output)
# 计算隐藏层梯度
hidden_error = []
for i in range(len(w2)):
hidden_error.append(output_delta * w2[i][0])
hidden_delta = [hidden_error[i] * sigmoid_derivative(hidden_output[i]) for i in range(len(hidden_error))]
# 更新隐藏层到输出层的权重和偏置
for i in range(len(w2)):
w2[i][0] -= learning_rate * output_delta * hidden_output[i]
b2[0] -= learning_rate * output_delta
# 更新输入层到隐藏层的权重和偏置
for i in range(len(w1)):
for j in range(len(w1[i])):
w1[i][j] -= learning_rate * hidden_delta[j] * input_data[i]
for i in range(len(b1)):
b1[i] -= learning_rate * hidden_delta[i]
return w1, b1, w2, b2
6. 完整训练流程
将以上步骤串联,实现完整的模型训练过程,这里使用简单的异或问题作为训练数据:
# 训练数据:异或问题,输入两个0或1的值,相同输出0,不同输出1
train_data = [
[[0, 0], 0],
[[0, 1], 1],
[[1, 0], 1],
[[1, 1], 0]
]
# 初始化参数
w1, b1, w2, b2 = init_parameters()
# 训练迭代
epochs = 10000
for epoch in range(epochs):
total_loss = 0
for input_data, true_value in train_data:
# 前向传播
hidden_output, predict = forward_propagation(input_data, w1, b1, w2, b2)
# 计算损失
loss = mse_loss(predict, true_value)
total_loss += loss
# 反向传播更新参数
w1, b1, w2, b2 = backward_propagation(input_data, hidden_output, predict, true_value, w1, b1, w2, b2)
# 每1000次迭代打印一次损失
if epoch % 1000 == 0:
print(f"Epoch {epoch}, Loss: {total_loss / len(train_data)}")
# 测试训练后的模型
print("训练完成后测试结果:")
for input_data, true_value in train_data:
_, predict = forward_propagation(input_data, w1, b1, w2, b2)
print(f"输入:{input_data},真实值:{true_value},预测值:{predict:.4f}")
训练结果说明
经过10000次迭代后,模型在异或问题上的预测值会非常接近真实值,损失函数会持续下降。如果训练效果不好,可以适当调整学习率、增加迭代次数或者调整网络结构。这种从零实现的方式虽然计算效率不如成熟框架,但能帮助开发者彻底理解神经网络的工作逻辑,为后续使用框架开发复杂模型打下基础。
注意事项
- 纯Python实现的矩阵运算效率较低,处理大规模数据建议引入numpy优化计算
- 学习率过大会导致损失震荡无法收敛,过小会导致收敛速度过慢,需要根据实际情况调整
- 复杂网络的参数初始化、激活函数选择都会影响训练效果,实际应用中需要结合场景调整