手写数字识别

数据集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 ✓

完整训练流程

  1. 前向传播:输入→网络计算→预测输出
  2. 计算损失:真实值与预测值差异
  3. 反向传播:计算损失对每个参数的梯度
  4. 参数更新:沿着梯度反方向调整参数
  5. 重复:直到损失足够小或达到训练轮数

损失函数loss function

通过损失函数来量化预测值与真实值之间的误差。

均方误差(MSE):回归问题(预测一个连续的数值)

MSE=1ni=1n(yiy^i)2\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2

交叉熵(Cross-Entropy):分类问题(预测一个离散的类别标签)

二分类交叉熵损失

L=1Ni=1N[yilog(pi)+(1yi)log(1pi)]L = - \frac{1}{N} \sum_{i=1}^{N} \left[ y_i \cdot \log(p_i) + (1 - y_i) \cdot \log(1 - p_i) \right]

其中:

  • NN 是样本数量
  • yiy_i 是第 ii 个样本的真实标签,通常取值为 0 或 1
  • pip_i 是模型预测第 ii 个样本属于类别 1 的概率,取值范围为 (0, 1)

多分类交叉熵损失函数

L=1Nn=1Ni=1Cyn,ilog(pn,i)\mathcal{L} = -\frac{1}{N} \sum_{n=1}^{N} \sum_{i=1}^{C} y_{n,i} \log(p_{n,i})

符号 含义 维度/取值范围
NN 批量大小(样本数量) 正整数
CC 类别总数 正整数
yn,iy_{n,i} nn 个样本的第 ii 个类别的真实标签 0 或 1(one-hot)
pn,ip_{n,i} nn 个样本的第 ii 个类别的预测概率 [0, 1]
L\mathcal{L} 批量平均损失 0\geq 0
log\log 自然对数(通常以 ee 为底) -

图片转换为张量

实质是将图像中的像素值提取出来,按照一定的规则组织成一个多维数组。

图片分类:

  • 灰度图像:一个像素是一个单独的数值,在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...│
    └─────────────┘    └─────────────┘    └─────────────┘
""")