第3课_实现一个前馈神经网络
热度🔥:55 免费课程
授课语音
实践:实现一个简单的前馈神经网络用于分类任务
在这部分实践中,我们将构建一个简单的前馈神经网络(Feedforward Neural Network, FNN),用于解决分类任务。我们将使用Python和NumPy库来实现神经网络,并通过前向传播和反向传播来训练网络。
1. 问题描述
我们将使用一个简单的分类任务,假设我们有一个二分类问题,目标是根据输入的特征来预测类别。比如,通过两维数据(例如:身高和体重)来预测某人是否患有某种疾病(1为患病,0为健康)。
2. 神经网络架构
我们的神经网络将包含以下结构:
- 输入层:2个输入节点(代表两个特征:身高和体重)。
- 隐藏层:1个隐藏层,包含3个神经元,使用ReLU激活函数。
- 输出层:1个输出节点,输出类别,使用Sigmoid激活函数。
3. 前向传播与反向传播
我们将使用 ReLU 作为隐藏层的激活函数,Sigmoid 作为输出层的激活函数,损失函数使用 二元交叉熵(Binary Cross-Entropy),并使用 梯度下降 来更新权重。
4. 代码实现
import numpy as np
# 激活函数
def relu(x):
return np.maximum(0, x)
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
def relu_derivative(x):
return np.where(x > 0, 1, 0)
# 初始化权重和偏置
def initialize_weights(input_size, hidden_size, output_size):
np.random.seed(42) # 固定种子,确保结果可复现
weights_1 = np.random.randn(input_size, hidden_size) # 输入到隐藏层的权重
bias_1 = np.zeros((1, hidden_size)) # 隐藏层的偏置
weights_2 = np.random.randn(hidden_size, output_size) # 隐藏层到输出层的权重
bias_2 = np.zeros((1, output_size)) # 输出层的偏置
return weights_1, bias_1, weights_2, bias_2
# 前向传播
def forward_propagation(X, weights_1, bias_1, weights_2, bias_2):
z1 = np.dot(X, weights_1) + bias_1
a1 = relu(z1) # 隐藏层激活
z2 = np.dot(a1, weights_2) + bias_2
output = sigmoid(z2) # 输出层激活
return a1, output
# 反向传播
def backpropagation(X, y, a1, output, weights_1, weights_2, bias_1, bias_2, learning_rate):
m = X.shape[0]
# 计算输出层的误差
error_output = output - y
d_weights_2 = np.dot(a1.T, error_output) / m
d_bias_2 = np.sum(error_output, axis=0, keepdims=True) / m
# 计算隐藏层的误差
error_hidden = np.dot(error_output, weights_2.T) * relu_derivative(a1)
d_weights_1 = np.dot(X.T, error_hidden) / m
d_bias_1 = np.sum(error_hidden, axis=0, keepdims=True) / m
# 更新权重和偏置
weights_1 -= learning_rate * d_weights_1
bias_1 -= learning_rate * d_bias_1
weights_2 -= learning_rate * d_weights_2
bias_2 -= learning_rate * d_bias_2
return weights_1, bias_1, weights_2, bias_2
# 训练神经网络
def train_neural_network(X, y, input_size, hidden_size, output_size, epochs, learning_rate):
weights_1, bias_1, weights_2, bias_2 = initialize_weights(input_size, hidden_size, output_size)
for epoch in range(epochs):
# 前向传播
a1, output = forward_propagation(X, weights_1, bias_1, weights_2, bias_2)
# 计算损失(交叉熵)
loss = -np.mean(y * np.log(output) + (1 - y) * np.log(1 - output))
# 反向传播
weights_1, bias_1, weights_2, bias_2 = backpropagation(X, y, a1, output, weights_1, weights_2, bias_1, bias_2, learning_rate)
# 每1000次迭代输出一次损失
if epoch % 1000 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
return weights_1, bias_1, weights_2, bias_2
# 预测函数
def predict(X, weights_1, bias_1, weights_2, bias_2):
_, output = forward_propagation(X, weights_1, bias_1, weights_2, bias_2)
return (output > 0.5).astype(int) # 将输出转换为0或1
# 示例数据(假设为身高和体重来预测是否患病)
X = np.array([[1.7, 65], [1.8, 80], [1.6, 55], [1.7, 70], [1.75, 75], [1.8, 90]]) # 输入特征
y = np.array([[0], [1], [0], [0], [1], [1]]) # 输出标签,0表示健康,1表示患病
# 训练模型
input_size = X.shape[1] # 输入特征数
hidden_size = 3 # 隐藏层神经元数量
output_size = 1 # 输出层神经元数量
epochs = 10000 # 训练轮数
learning_rate = 0.01 # 学习率
weights_1, bias_1, weights_2, bias_2 = train_neural_network(X, y, input_size, hidden_size, output_size, epochs, learning_rate)
# 预测
predictions = predict(X, weights_1, bias_1, weights_2, bias_2)
print(f"Predictions: {predictions.T}")
5. 代码解释
激活函数:
relu(x)
:ReLU激活函数,用于隐藏层。sigmoid(x)
:Sigmoid激活函数,用于输出层。sigmoid_derivative(x)
和relu_derivative(x)
:分别用于计算Sigmoid和ReLU的导数,供反向传播使用。
初始化权重和偏置:
initialize_weights()
函数随机初始化网络的权重和偏置。
前向传播:
forward_propagation()
函数用于计算前向传播,输出每一层的激活值,最终得到输出层的预测值。
反向传播:
backpropagation()
函数计算损失函数对每一层的权重和偏置的梯度,并使用梯度下降法更新权重。
训练函数:
train_neural_network()
函数使用前向传播和反向传播训练神经网络,并且每隔1000次迭代输出损失值。
预测:
predict()
函数根据训练后的网络权重预测新样本的分类。
6. 结果展示
运行代码后,训练过程中的损失值会逐步下降,最后输出每个样本的预测结果。例如:
Epoch 0, Loss: 0.6901
Epoch 1000, Loss: 0.6882
Epoch 2000, Loss: 0.6859
...
Predictions: [[0 1 0 0 1 1]]
这些预测值表示每个输入样本的分类结果,0表示健康,1表示患病。
7. 总结
- 我们实现了一个简单的前馈神经网络,通过前向传播和反向传播算法进行训练,并使用梯度下降法优化网络的权重。
- 通过这种方式,我们可以使用神经网络来处理分类问题,并根据输入特征预测类别。
- 这种简单的网络为我们进一步理解和扩展更复杂的神经网络模型(如卷积神经网络、循环神经网络等)奠定了基础。
这个实践提供了神经网络训练的基本框架,并能帮助学员掌握前馈神经网络的核心概念。