完成作业3.3.2
This commit is contained in:
172
digit_mlp_class/README.md
Normal file
172
digit_mlp_class/README.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# 手写数字识别 - 纯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数据集处理
|
||||
Reference in New Issue
Block a user