引言:作为一名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.5
    self.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).T
    targets = 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_outputs
    hidden_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 = 0

for train_image, train_label in zip(train_images, train_labels):
    n.fit(train_image, train_label)
i = i + 1

    print(f"\r完成第{i}次训练", end='', flush=True)

训练细节:
1.采用随机梯度下降(SGD),每次输入一个样本
2.使用进度显示直观展示训练进度
3.学习率设置为0.02(经实验调整后的较优值)
4.完整训练需要遍历60,000张图片

六、模型评估与测试

6.1训练完成后,在测试集上评估模型性能:

scores = []
j = 0

for 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 + 1

    print(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)提升图像识别准确率

学习感悟:从理论到实践的跨越充满挑战,但每次成功运行代码、看到准确率提升都带来巨大成就感。这个简单但完整的项目为我打开了深度学习的大门,期待在计算机视觉领域继续探索!

更多推荐