手写数字识别:从图像到神经网络
手写数字识别
数据集MNIST
图片:28*28像素 灰度值:0~255之间 每张图片带有一个标记,就是该图片的真实值
训练集:6万张
测试集:1万张
思考:通过不同的神经网络进行测试集真实值的判断,通过不同的神经网络的输入来看,都是以向量的形式,但是如何将图片转化为向量呢?
解:假设图片大小是5*5,那么将像素重新排列成一维阵列,共25个像素,构成神经网络的第0层,每个节点值为0或者1。
所以28*28像素的图片构成的一维阵列就是784个像素,组成了一个[784,1]的矩阵向量。
通过FNN进行识别
单张图片
单个神经元
- x是输入向量,784*1
- a是一个权重向量,对于第一个隐藏层的神经元,a大小就是1*784
- b是偏置项,是一个标量
计算z=a*x+b得到标量z,因为(1,784) * (784,1) = (1,1)也就是一个标量,通过激活函数得到该神经元的输出a_out = σ(z)
但是,神经网络一层通常有多个神经元,使用矩阵运算一次性处理整个层。
整层多个神经元
- x输入向量,784*1
- 假设第一个隐藏层有256个神经元,每一个神经元都有自己的权重向量a_i(大小为1*784)和自己的偏置项b_i
将a_i堆叠起来得到该层的权重矩阵w1(大小为256 * 784),256是该层神经元个数,784是前一层神经元的数量或者输入维度。
同样,将b_i堆叠起来,得到该层的偏执向量b1(大小为256*1)
所以整层的矩阵计算为:z1 = w1 * x + b1
批量图片
实际训练中,不会一张一张图片的进行处理,而是多张图片组合成单批次Batch进行处理。
原因:
- GPU擅长并行计算
- 与损失函数有关
单批次整层多个神经元
- X_single:一张图片,784*1
- X_batch:单批次数据输入,将每张图片作为一列,维度为784*B,B表示批次大小,即单批次中有多少张图片
- 权重矩阵:w1,256 * 784,形状不变
- 偏执矩阵:b1,256 *1
矩阵计算:z1 = w1 * X_batch + b1
部分结论
- 输入层和输出层(分类多少)的大小是固定的
- 隐藏层数量(深度):浅层网络1-2层适用于MNIST这种相对简单的问题,复杂的问题需要更深的网络
- 隐藏层的大小(宽度):
- 常见做法是逐层递减784→512→256→10,随着网络的深入,学习到的特征越来越抽象,不需要那么多神经元来编码
- 或者使用相同大小的隐藏层784→256→256→10
- 可以看到大部分参数的计算基本在前面的神经层中进行,所以输入数据维度对模型大小影响巨大
- 权重矩阵与偏执矩阵的维度大小与批次大小B无关,只与网络结构本身有关
激活函数
防止多层网络退化成为线性变换
Sigmoid: σ(z) = 1/(1+e⁻ᶻ)
- 输出范围:(0,1)
- 问题:梯度消失,输出不是零中心
ReLU: f(z) = max(0,z)
- 最常用!计算简单,缓解梯度消失
- 问题:负数区完全失效
Tanh: tanh(z) = (eᶻ-e⁻ᶻ)/(eᶻ+e⁻ᶻ)
- 输出范围:(-1,1),零中心
- 比sigmoid更好
softmax
输出层将网络层输出转换为概率分布(0-1)
Softmax公式:
对于输出向量 z = [z₁, z₂, z₃]ᵀ
softmax(zᵢ) = eᶻⁱ / (eᶻ¹ + eᶻ² + eᶻ³)
示例:
-
网络输出:z = [2.0, 1.0, 0.1]ᵀ
-
softmax计算:
- eᶻ¹ = e²·⁰ ≈ 7.389
- eᶻ² = e¹·⁰ ≈ 2.718
- eᶻ³ = e⁰·¹ ≈ 1.105
- 总和 = 11.212
-
概率分布:
- p₁ = 7.389/11.212 ≈ 0.659
- p₂ = 2.718/11.212 ≈ 0.242
- p₃ = 1.105/11.212 ≈ 0.099
- 总和 = 1.000 ✓
完整训练流程
- 前向传播:输入→网络计算→预测输出
- 计算损失:真实值与预测值差异
- 反向传播:计算损失对每个参数的梯度
- 参数更新:沿着梯度反方向调整参数
- 重复:直到损失足够小或达到训练轮数
损失函数loss function
通过损失函数来量化预测值与真实值之间的误差。
均方误差(MSE):回归问题(预测一个连续的数值)
交叉熵(Cross-Entropy):分类问题(预测一个离散的类别标签)
二分类交叉熵损失
其中:
- 是样本数量
- 是第 个样本的真实标签,通常取值为 0 或 1
- 是模型预测第 个样本属于类别 1 的概率,取值范围为 (0, 1)
多分类交叉熵损失函数
| 符号 | 含义 | 维度/取值范围 |
|---|---|---|
| 批量大小(样本数量) | 正整数 | |
| 类别总数 | 正整数 | |
| 第 个样本的第 个类别的真实标签 | 0 或 1(one-hot) | |
| 第 个样本的第 个类别的预测概率 | [0, 1] | |
| 批量平均损失 | ||
| 自然对数(通常以 为底) | - |
图片转换为张量
实质是将图像中的像素值提取出来,按照一定的规则组织成一个多维数组。
图片分类:
- 灰度图像:一个像素是一个单独的数值,在0-255之间
- 彩色图像:每个像素由三个数值表示,代表红绿蓝通道的强度,每个通道的数值在0-255之间
转换结果:
- 灰度图像 → 二维张量
- 彩色图像 → 三维张量
pytorch中的图像数据转换为张量进行神经网络计算时使用到了transforms.ToTensor()的变换:
- 维度重排:(H, W, C) → (C, H, W)
- 类型转换:uint8 → float32
- 数值缩放:[0, 255] → [0.0, 1.0]
示例:
print("\n=== 维度变换示意图 ===")
print("转换前:原始图像数组结构")
print("""
宽度(5列)
┌─────────────────┐
高 │ (5,5,3) │
度 │ [行, 列, 通道] │
(5 │ │
行) │ 每个位置有3个值: │
│ [R, G, B] │
└─────────────────┘
""")
print("转换后:张量结构")
print("""
张量形状:[3, 5, 5]
第0层:R通道(5×5) 第1层:G通道(5×5) 第2层:B通道(5×5)
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 1.00 0.78...│ │ 0.00 0.00...│ │ 0.00 0.00...│
│ 0.00 0.00...│ │ 0.78 0.78...│ │ 0.00 0.00...│
│ 0.00 0.00...│ │ 0.00 0.00...│ │ 1.00 0.78...│
│ 1.00 1.00...│ │ 1.00 0.00...│ │ 0.00 0.00...│
│ 1.00 0.50...│ │ 0.50 1.00...│ │ 0.00 0.00...│
└─────────────┘ └─────────────┘ └─────────────┘
""")
