# 手写数字识别 - 纯NumPy MLP实现 ## 项目简介 使用纯NumPy实现的两层全连接神经网络(MLP),在MNIST数据集上进行手写数字识别。 **零深度学习框架依赖**,只需 `numpy`。 ## 网络结构 ``` 输入层(784) → 隐藏层(128) + ReLU → 输出层(10) + Softmax ``` - **输入**: 28×28=784 像素值,归一化到 [0, 1] - **隐藏层**: 128 神经元,ReLU激活函数 - **输出层**: 10 神经元(数字0-9),Softmax输出概率 ## 文件结构 ``` digit_mlp_class/ ├── main.py # 主程序(训练/评估/对比实验) ├── model_numpy.py # MLP模型(纯NumPy实现) ├── dataset.py # MNIST数据集加载 ├── config.py # 超参数配置 ├── data/ # MNIST数据文件 │ ├── train-images-idx3-ubyte.gz │ ├── train-labels-idx1-ubyte.gz │ ├── t10k-images-idx3-ubyte.gz │ └── t10k-labels-idx1-ubyte.gz └── README.md ``` ## 依赖 ``` numpy ``` ## 使用方法 ### 1. 下载MNIST数据集 如果 `data/` 目录下没有数据文件,运行: ```bash python dataset.py ``` 或手动下载: ```bash cd data/ curl -LO https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz curl -LO https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz curl -LO https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz curl -LO https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz ``` ### 2. 训练模型 ```bash python main.py ``` ### 3. 运行对比实验 ```bash python main.py --compare ``` ## 代码设计 ### model_numpy.py - MLP模型 核心实现: - **前向传播**: 矩阵乘法 + ReLU + Softmax - **反向传播**: 手动梯度计算 + 梯度下降 - **权重初始化**: Xavier初始化(适合ReLU) ```python class MLP: def __init__(self, input_size=784, hidden_size=128, num_classes=10) def forward(self, X): # 前向传播 def backward(self, X, y): # 反向传播 def fit(self, X, y): # 训练 def predict(self, X): # 预测 ``` ### dataset.py - 数据加载 - 自动检测 `data/` 目录下的MNIST文件 - 解析IDX格式(MNIST标准格式) - 归一化像素值到 [0, 1] - 支持One-Hot编码标签 ### main.py - 主程序 两种运行模式: 1. **默认模式**: 训练一个模型并评估 2. **对比模式** (`--compare`): 对比不同超参数的效果 ## 数学原理 ### 前向传播 ``` z1 = X @ W1 + b1 # 第一层线性变换 a1 = ReLU(z1) # 第一层激活 z2 = a1 @ W2 + b2 # 第二层线性变换 probs = softmax(z2) # 输出概率 ``` ### 反向传播 ``` d_z2 = probs - y # 输出层梯度 d_W2 = a1.T @ d_z2 # 第二层权重梯度 d_z1 = d_z2 @ W2.T * relu_derivative(z1) # 隐藏层梯度 d_W1 = X.T @ d_z1 # 第一层权重梯度 W1 -= lr * d_W1 / batch_size # 梯度下降更新 W2 -= lr * d_W2 / batch_size ``` ### 激活函数 **ReLU**: ``` ReLU(x) = max(0, x) ReLU'(x) = 1 if x > 0 else 0 ``` **Softmax**: ``` softmax(x_i) = exp(x_i) / sum(exp(x_j)) ``` ## 超参数 | 参数 | 默认值 | 说明 | |------|--------|------| | hidden_size | 128 | 隐藏层神经元数量 | | learning_rate | 0.1 | 学习率 | | epochs | 50 | 训练轮数 | | batch_size | 64 | 批大小 | | seed | 42 | 随机种子 | ## 预期结果 - 训练准确率: ~98% - 测试准确率: ~95-97% 训练时间: 约 5-10 分钟(取决于硬件) ## 扩展实验 1. **改变隐藏层大小**: 32 / 64 / 128 / 256 2. **改变学习率**: 0.01 / 0.1 / 0.5 3. **添加Dropout**: 防止过拟合 4. **增加隐藏层数**: 784 → 256 → 128 → 10 ## 教学用途 本项目适合用于讲解: - 神经网络基本结构 - 前向传播与反向传播原理 - 梯度下降优化 - NumPy矩阵操作 - MNIST数据集处理