机器学习————神经网络
一、核心概念
1.基本定义
神经网络是一种模仿人脑神经元结构的机器学习模型,由输入层、隐藏层、输出层组成,核心是通过数据驱动的方式学习输入与输出之间的映射关系。
(注:通过输入层、隐藏层、输出层顺序串联,完成从原始数据到最终预测结果的转换,就像工厂的 “原材料接收→加工生产→成品输出” 流水线,且只有输入层和输出层是 “可见层”,直接对接数据和结果;隐藏层是网络的 “黑箱核心”,负责特征学习和数据变换。)
2.核心流程
1. 前向传播——预测环节
数据从输入层进入,依次经过隐藏层、输出层:
- 输入层:只传递原始数据,如图像像素、文字特征,不做任何处理,神经元数量和数据维度一致;
- 隐藏层:网络的 “核心加工区”,通过权重调整输入信号的重要性,再用激活函数做非线性转换,把原始数据变成有意义的特征,如从像素提取图像边缘、笔画,层数和神经元数量可自定义;
- 输出层:把隐藏层的特征转化为最终结果,神经元数量和任务目标匹配,如识别 0-9 数字就设 10 个神经元,输出结果贴合任务,其中分类输出概率,回归输出连续值。
2. 激活函数
给隐藏层、输出层加的 “转换规则”,让网络能识别非线性规律,比如区分圆形和方形。不同场景选不同类型:隐藏层常用 ReLU(简单高效),二分类输出层用 Sigmoid(输出 0-1 概率),多分类用 Softmax(输出各类概率总和为 1)。
3.反向传播 + 梯度下降
这是网络 “自我修正” 的核心,目的是减少预测误差:
- 损失函数:先判断预测结果和真实结果的差距,误差越大,后续调整幅度越大;
- 反向传播:从输出层往回推,找出每个权重、偏置对误差的影响,明确 “该调整哪些参数”;
- 梯度下降:沿着 “减少误差” 的方向,逐步微调所有权重和偏置,让下次预测更准确。优化器是梯度下降的升级工具,能让调整更高效、更稳定。
二、数学原理
1. 计算前提
神经元
作用:神经网络的基本单元,接收输入→加权求和→激活函数→输出。
权重 (W)
作用:神经元之间连接的强度,模型学习的核心参数。
偏置 (b)
作用:调整神经元输出的基准值,解决加权求和后结果可能偏离有效范围的问题。
激活函数
作用:引入非线性,让网络能拟合复杂的非线性关系(如 ReLU、Sigmoid、Tanh)。
损失函数
作用:衡量预测值与真实值的差距(如 MSE、交叉熵)。
反向传播
作用:沿着损失函数下降的方向,反向更新权重和偏置,核心是链式求导。
梯度下降
作用:优化算法,通过迭代更新参数,最小化损失函数。
2、计算公式
1. 单个神经元
设神经元接收输入,对应的权重为
w1,w2,...,wn,偏置为 b,激活函数为 f(⋅)。
则神经元输出:
2. 单层神经网络——感知机
输入层有 m 个神经元,隐藏层有 k 个神经元,则:
- 输入矩阵
,其中N 为样本数;
- 权重矩阵
;
- 偏置向量
;
- 隐藏层输出:
。
3. 反向传播核心
设输出层输出为 ,真实值为 y,损失函数
。
反向传播的本质是用链式法则求损失对每个参数的偏导数。
4. 梯度下降更新规则
参数更新公式(η 为学习率):
三、代码解释
用 Python 实现一个两层神经网络,输入层 + 1 个隐藏层 + 输出层。
模块一:数据库导入
# 导入numpy库,用于数值计算(矩阵运算、随机数生成等),是神经网络的核心计算库
import numpy as np
# 从tensorflow.keras.datasets导入mnist数据集(手写数字识别经典数据集)
from tensorflow.keras.datasets import mnist
# 从tensorflow.keras.utils导入to_categorical,用于标签的独热编码
from tensorflow.keras.utils import to_categorical
模块二:数据预处理
reshape(-1, 784):将 28×28 的二维图片展平为 784 维的一维向量,适配神经网络输入层;- 归一化:将像素值除以 255 缩放到 [0,1],避免大数值导致权重更新不稳定;
- 独热编码:将标签转为 10 维向量,适配输出层的 10 个神经元(每个神经元对应一个数字的概率)。
# 加载MNIST数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 1.1 归一化:将像素值从[0,255]缩放到[0,1],加速训练
x_train = x_train.reshape(-1, 784) / 255.0 # 28*28=784,展平为一维向量
x_test = x_test.reshape(-1, 784) / 255.0
# 1.2 标签独热编码:将数字标签(0-9)转为10维独热向量(如3→[0,0,0,1,0,0,0,0,0,0])
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
模块三:神经网络核心类
- 初始化(init):
- 权重初始化采用 Xavier 初始化,除以输入维度的平方根)】,解决 ReLU 激活函数下的梯度消失问题;
- 偏置初始化为 0,学习率默认设为 0.1,可根据训练效果调整。
- 激活函数:
- ReLU:max(0,1),计算简单、缓解梯度消失,是隐藏层最常用的激活函数;
- Softmax:将输出转为概率分布,满足多分类任务 “概率和为 1” 的要求。
- 前向传播(forward):严格遵循 “加权求和(z)→激活函数(a)” 的流程,依次计算隐藏层和输出层的输出,同时保存中间结果(z1、a1、z2、a2)供反向传播使用。
- 反向传播(backward):核心是链式求导,步骤为:
- 计算输出层梯度(dz2、dW2、db2);
- 链式推导隐藏层梯度(dz1、dW1、db1);
- 用梯度下降更新所有权重和偏置。
- 损失函数(compute_loss):交叉熵损失是多分类任务的标准损失函数,加
1e-8防止log(0)导致数值错误。
class SimpleNN:
def __init__(self, input_size, hidden_size, output_size, learning_rate=0.1):
"""
初始化神经网络参数
:param input_size: 输入层神经元数(MNIST为784)
:param hidden_size: 隐藏层神经元数
:param output_size: 输出层神经元数(MNIST为10)
:param learning_rate: 学习率
"""
# 初始化权重(使用Xavier初始化,避免梯度消失/爆炸)
self.W1 = np.random.randn(input_size, hidden_size) / np.sqrt(input_size/2)
self.b1 = np.zeros((1, hidden_size)) # 隐藏层偏置
self.W2 = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size/2)
self.b2 = np.zeros((1, output_size)) # 输出层偏置
self.lr = learning_rate # 学习率
def relu(self, x):
"""ReLU激活函数:f(x)=max(0,x),引入非线性"""
return np.maximum(0, x)
def relu_derivative(self, x):
"""ReLU导数:x>0时为1,x≤0时为0"""
return np.where(x > 0, 1, 0)
def softmax(self, x):
"""Softmax激活函数:将输出转为概率分布(所有值和为1),用于多分类"""
# 防止数值溢出:减去每行最大值
exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
def forward(self, x):
"""前向传播:从输入到输出的计算过程"""
# 隐藏层计算
self.z1 = np.dot(x, self.W1) + self.b1 # 加权求和
self.a1 = self.relu(self.z1) # 激活函数输出
# 输出层计算
self.z2 = np.dot(self.a1, self.W2) + self.b2 # 加权求和
self.a2 = self.softmax(self.z2) # 激活函数输出(概率)
return self.a2
def backward(self, x, y):
"""反向传播:计算参数梯度并更新"""
batch_size = x.shape[0]
# 输出层梯度
dz2 = self.a2 - y # 损失对z2的偏导(交叉熵+softmax的简化结果)
dW2 = np.dot(self.a1.T, dz2) / batch_size # 损失对W2的偏导
db2 = np.sum(dz2, axis=0, keepdims=True) / batch_size # 损失对b2的偏导
# 隐藏层梯度(链式法则)
dz1 = np.dot(dz2, self.W2.T) * self.relu_derivative(self.z1) # 损失对z1的偏导
dW1 = np.dot(x.T, dz1) / batch_size # 损失对W1的偏导
db1 = np.sum(dz1, axis=0, keepdims=True) / batch_size # 损失对b1的偏导
# 梯度下降更新参数
self.W1 -= self.lr * dW1
self.b1 -= self.lr * db1
self.W2 -= self.lr * dW2
self.b2 -= self.lr * db2
def compute_loss(self, y_pred, y_true):
"""计算交叉熵损失(多分类任务常用)"""
# 防止log(0):加极小值epsilon
epsilon = 1e-8
return -np.sum(y_true * np.log(y_pred + epsilon)) / y_pred.shape[0]
模块四:训练与测试
# 初始化网络
nn = SimpleNN(input_size=784, hidden_size=128, output_size=10, learning_rate=0.1)
# 超参数设置
epochs = 20 # 训练轮数
batch_size = 64 # 批次大小
n_batches = x_train.shape[0] // batch_size # 每轮训练的批次数
# 训练过程
for epoch in range(epochs):
# 打乱训练数据(防止过拟合)
indices = np.random.permutation(x_train.shape[0])
x_train_shuffled = x_train[indices]
y_train_shuffled = y_train[indices]
total_loss = 0
# 按批次训练
for i in range(n_batches):
# 取当前批次数据
start = i * batch_size
end = start + batch_size
x_batch = x_train_shuffled[start:end]
y_batch = y_train_shuffled[start:end]
# 前向传播计算预测值
y_pred = nn.forward(x_batch)
# 计算损失
loss = nn.compute_loss(y_pred, y_batch)
total_loss += loss
# 反向传播更新参数
nn.backward(x_batch, y_batch)
# 每轮训练后打印损失
avg_loss = total_loss / n_batches
print(f"Epoch {epoch+1}/{epochs}, Average Loss: {avg_loss:.4f}")
# 测试模型
y_test_pred = nn.forward(x_test)
# 预测结果:取概率最大的索引(即预测的数字)
test_pred_labels = np.argmax(y_test_pred, axis=1)
test_true_labels = np.argmax(y_test, axis=1)
# 计算准确率
accuracy = np.mean(test_pred_labels == test_true_labels)
print(f"\nTest Accuracy: {accuracy:.4f}")
运行结果
Epoch 1/20, Average Loss: 0.3662
Epoch 2/20, Average Loss: 0.1968
Epoch 3/20, Average Loss: 0.1496
Epoch 4/20, Average Loss: 0.1212
Epoch 5/20, Average Loss: 0.1026
Epoch 6/20, Average Loss: 0.0890
Epoch 7/20, Average Loss: 0.0778
Epoch 8/20, Average Loss: 0.0696
Epoch 9/20, Average Loss: 0.0626
Epoch 10/20, Average Loss: 0.0567
Epoch 11/20, Average Loss: 0.0514
Epoch 12/20, Average Loss: 0.0472
Epoch 13/20, Average Loss: 0.0431
Epoch 14/20, Average Loss: 0.0396
Epoch 15/20, Average Loss: 0.0363
Epoch 16/20, Average Loss: 0.0340
Epoch 17/20, Average Loss: 0.0314
Epoch 18/20, Average Loss: 0.0290
Epoch 19/20, Average Loss: 0.0267
Epoch 20/20, Average Loss: 0.0250
Test Accuracy: 0.9778
- 训练损失:持续下降且最终极低(0.025),说明模型在训练集上完全学会了手写数字的规律;
- 测试准确率:97.78% 的高准确率,说明模型的规律学习不是 “死记硬背”,而是能迁移到新数据上,泛化能力优秀;
- 模型状态:收敛良好、无过拟合或欠拟合,是一份 “近乎完美” 的新手实战结果。
四、总结
核心要点回顾
- 神经网络本质:通过权重和偏置的学习,实现输入到输出的非线性映射,核心是 “前向传播算输出,反向传播更参数”;
- 数学核心:前向传播基于线性组合 + 激活函数,反向传播基于链式法则求梯度,参数更新基于梯度下降;
- 代码关键:
- 激活函数引入非线性(ReLU+Softmax);
- 反向传播需保存前向传播的中间结果;
- 批次训练和数据打乱是提升模型效果的重要方法。
感谢大家的观看!有缺点和不足,请大家指正!
更多推荐

所有评论(0)