从零开始:手写数字识别程序的深度学习实践
从零开始:手写数字识别程序的深度学习实践
- 一、环境搭建与数据准备
- 二、加载数据集
- 三、神经网络类设计与实现
- 3.1 初始化方法
- 3.2 训练方法(核心)
- 3.3 预测方法
- 四、数据预处理:为模型输入做准备
- 4.1训练数据处理
- 4.2测试数据处理
- 4.3标签转换为one-hot编码
- 五、模型训练过程解析
- 5.1初始化网络并开始训练:
- 六、模型评估与测试
- 6.1训练完成后,在测试集上评估模型性能:
- 七、总结与学习心得
- 7.1 核心收获
- 7.2 遇到的问题与解决
- 7.3 改进方向
引言:作为一名AI初学者,我选择从经典的MNIST手写数字识别项目开始深度学习之旅。本文记录了我根据书本参考代码,从零开始实现一个能够识别0-9手写数字程序的全过程。通过这个项目,我深刻理解了神经网络的基本原理和实现细节。
一、环境搭建与数据准备
在项目开始前,需要搭建Python环境并导入必要的库:
import numpy
from keras.datasets import mnist
import scipy.special
from keras.utils import to_categorical
关键库的作用:
1.numpy:科学计算基础库,处理矩阵运算
2.keras.datasets:提供经典数据集(这里使用MNIST)
3.scipy.special:包含特殊数学函数(如sigmoid)
4.to_categorical:将标签转换为one-hot编码
二、加载数据集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
MNIST数据集包含:
1.60,000张28×28像素的训练图片
2.10,000张测试图片
3.每张图片对应0-9的数字标签
三、神经网络类设计与实现
实现了一个三层全连接神经网络类NeuralNetWork:
3.1 初始化方法
def __init__(self, _input_nodes, _hidde_nodes, _output_nodes, _learning_rate):self.inputnodes = _input_nodes # 输入层节点数(784)self.hiddenodes = _hidde_nodes # 隐藏层节点数(100)self.outputnodes = _output_nodes # 输出层节点数(10)self.lr = _learning_rate # 学习率# 初始化权重矩阵(-0.5到0.5的随机值)self.wih = numpy.random.rand(self.hiddenodes, self.inputnodes) - 0.5self.who = numpy.random.rand(self.outputnodes, self.hiddenodes) - 0.5
3.2 训练方法(核心)
def fit(self, inputs_list, targets_list):# 数据转换inputs = numpy.array(inputs_list, ndmin=2).Ttargets = numpy.array(targets_list, ndmin=2).T# 前向传播hidden_inputs = numpy.dot(self.wih, inputs)hidden_outputs = scipy.special.expit(hidden_inputs) # sigmoid激活final_inputs = numpy.dot(self.who, hidden_outputs)final_outputs = scipy.special.expit(final_inputs) # sigmoid激活# 误差计算output_errors = targets - final_outputshidden_errors = numpy.dot(self.who.T, output_errors)# 权重更新(反向传播)self.who += self.lr numpy.dot((output_errors final_outputs * (1 - final_outputs)), numpy.transpose(hidden_outputs))self.wih += self.lr numpy.dot((hidden_errors hidden_outputs * (1 - hidden_outputs)), numpy.transpose(inputs))
3.3 预测方法
def evaluate(self, inputs):# 前向传播计算输出hidden_inputs = numpy.dot(self.wih, inputs)hidden_outputs = scipy.special.expit(hidden_inputs)final_inputs = numpy.dot(self.who, hidden_outputs)final_outputs = scipy.special.expit(final_inputs)return final_outputs
四、数据预处理:为模型输入做准备
原始数据需要经过预处理才能输入神经网络:
4.1训练数据处理
train_images_number = 60000
train_images = train_images.reshape((train_images_number, 28 * 28)) # 扁平化
train_images = train_images.astype('float32') / 25 # 归一化
4.2测试数据处理
test_images_number = 10000
test_images = test_images.reshape(test_images_number, 28 * 28)
test_images = test_images.astype('float32') / 255 # 更精确的归一化
4.3标签转换为one-hot编码
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
数据处理要点:
1.扁平化:将28×28的二维图片转换为一维向量(784维)
2.归一化:像素值从[0,255]缩放到[0,1]区间
3.One-hot编码:数字标签转换为向量形式(如"3"变为[0,0,0,1,0,0,0,0,0,0])
五、模型训练过程解析
5.1初始化网络并开始训练:
#网络参数设置input_nodes = 784 # 对应28×28=784像素
hidden_nodes = 100 # 隐藏层神经元数量
output_nodes = 10 # 对应0-9十个数字
learning_rate = 0.02#初始化网络
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)#训练过程total = train_images_number
i = 0for train_image, train_label in zip(train_images, train_labels):n.fit(train_image, train_label)
i = i + 1print(f"\r完成第{i}次训练", end='', flush=True)
训练细节:
1.采用随机梯度下降(SGD),每次输入一个样本
2.使用进度显示直观展示训练进度
3.学习率设置为0.02(经实验调整后的较优值)
4.完整训练需要遍历60,000张图片
六、模型评估与测试
6.1训练完成后,在测试集上评估模型性能:
scores = []
j = 0for test_image, test_label in zip(test_images, test_labels):output = n.evaluate(test_image)evaluate_label = numpy.argmax(output) # 获取预测值correct_label = numpy.argmax(test_label) # 获取真实值
j = j + 1print(f"\r完成第{j}次测试", end='', flush=True)# 记录预测结果if evaluate_label == correct_label:scores.append(1)else:scores.append(0)#计算准确率scores_array = numpy.asarray(scores)
print("模型准确率为:", scores_array.sum() / scores_array.size)
评估逻辑:
1.遍历所有测试图片(10,000张)
2.模型预测输出10维概率向量
3.取最大概率值对应的索引作为预测数字
4.统计预测正确率
七、总结与学习心得
通过这个项目,我获得了以下宝贵经验:
7.1 核心收获
1.神经网络基础:深入理解了三层神经网络的前向传播、反向传播机制
2.数据预处理重要性:认识到归一化和数据格式转换对模型性能的关键影响
3.超参数调优:通过实验发现0.02的学习率比参考书的0.3更适合本模型
4.实践出真知:亲手调试代码比单纯看书更能理解算法细节
7.2 遇到的问题与解决
1.维度匹配错误:初次实现时因矩阵形状不匹配导致运算失败
解决:仔细检查每层输入的维度并添加转置操作
2.梯度消失问题:使用sigmoid激活函数在深层网络中出现梯度消失
解决:将隐藏层节点增加到100个缓解此问题
3.归一化差异:发现训练集和测试集使用了不同归一化系数
解决:统一使用/255进行标准化
7.3 改进方向
1.改用ReLU激活函数解决梯度消失问题
2.实现批量训练(Batch Training)提高效率
3.添加正则化技术减少过拟合
4.尝试卷积神经网络(CNN)提升图像识别准确率
学习感悟:从理论到实践的跨越充满挑战,但每次成功运行代码、看到准确率提升都带来巨大成就感。这个简单但完整的项目为我打开了深度学习的大门,期待在计算机视觉领域继续探索!