Python中的手写数字识别实例

1. 前言

随着深度学习技术的发展,图像识别已经成为了人工智能领域内不可或缺的部分。而手写数字识别作为图像识别的入门级任务,也成为了深度学习入门的经典案例之一。在本文中,我们将使用Python编写一个手写数字识别的实例,并通过自己编写的神经网络模型对手写数字图片进行识别。

2. 建立模型

2.1 导入必要的库

我们首先需要导入一些必要的库,包括:

numpy:用于高效的数值计算

tensorflow:用于搭建神经网络模型

matplotlib:用于可视化数据

pickle:用于序列化数据

gzip:用于压缩数据

random:用于随机化数据集

os:用于目录操作

import numpy as np

import tensorflow as tf

import matplotlib.pyplot as plt

import pickle

import gzip

import random

import os

2.2 声明一些常量

我们需要声明一些常量,用于我们的神经网络模型:

input_size:输入节点数

hidden_size:隐藏节点数

output_size:输出节点数

learning_rate:学习率

epochs:训练轮数

batch_size:每批次训练数量

input_size = 784

hidden_size = 512

output_size = 10

learning_rate = 0.001

epochs = 5

batch_size = 100

2.3 定义数据集

我们定义一个数据集结构体,用于存储训练数据和标签:

class Dataset:

def __init__(self, images, labels):

self.images = images

self.labels = labels

self.num_examples = len(images)

def shuffle(self):

perm = np.arange(self.num_examples)

np.random.shuffle(perm)

self.images = self.images[perm]

self.labels = self.labels[perm]

2.4 定义网络结构

我们使用三层神经网络进行手写数字识别。输入层大小为784(28x28的图像),隐层大小为512,输出层大小为10(对应0-9十个数字)。

网络中的权重和偏置变量使用TensorFlow提供的Variable定义,以便在反向传播时进行参数更新。

class Network:

def __init__(self, input_size, hidden_size, output_size):

self.input_size = input_size

self.hidden_size = hidden_size

self.output_size = output_size

self.W1 = tf.Variable(tf.random.normal([self.input_size, self.hidden_size]))

self.b1 = tf.Variable(tf.random.normal([self.hidden_size]))

self.W2 = tf.Variable(tf.random.normal([self.hidden_size, self.output_size]))

self.b2 = tf.Variable(tf.random.normal([self.output_size]))

def forward(self, x):

z1 = tf.matmul(x, self.W1) + self.b1

a1 = tf.nn.relu(z1)

z2 = tf.matmul(a1, self.W2) + self.b2

y = tf.nn.softmax(z2)

return y

2.5 定义损失函数和优化器

我们使用交叉熵作为损失函数,使用梯度下降法作为优化器。

def loss_fn(y, t):

cross_entropy = tf.reduce_mean(-tf.reduce_sum(t * tf.math.log(y), reduction_indices=[1]))

return cross_entropy

def train_step(model, x, t, optimizer):

with tf.GradientTape() as tape:

y = model.forward(x)

loss = loss_fn(y, t)

gradients = tape.gradient(loss, [model.W1, model.b1, model.W2, model.b2])

optimizer.apply_gradients(zip(gradients, [model.W1, model.b1, model.W2, model.b2]))

return loss

2.6 定义训练函数

我们定义一个训练函数,用于训练我们的神经网络模型。

在训练过程中,我们首先打乱数据集,然后将数据集分为多个batch。对于每个batch,我们向前传播计算输出和损失,然后使用梯度下降法进行反向传播,并更新权重和偏置变量。最后输出训练过程中的损失。

def train(model, dataset, optimizer, epochs, batch_size):

num_batches = dataset.num_examples // batch_size

for i in range(epochs):

dataset.shuffle()

for j in range(num_batches):

start = j * batch_size

end = start + batch_size

x_batch = dataset.images[start:end]

t_batch = dataset.labels[start:end]

loss = train_step(model, x_batch, t_batch, optimizer)

print("Epoch {}, loss: {}".format(i + 1, loss))

3. 获取MNIST数据集

我们使用MNIST数据集进行手写数字识别,可以通过tf.keras.datasets.mnist获取该数据集。

MNIST数据集包含60000张训练图片和10000张测试图片,每张图片大小为28x28像素。

(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

4. 数据预处理

我们需要对数据进行预处理,将每张图片的28x28像素展开为784个像素,并将像素值归一化到0-1之间。

然后将标签转换为one-hot编码,方便与神经网络的输出进行比较。

def preprocess(images, labels):

images = images.reshape(-1, 784).astype('float32') / 255.0

labels = np.eye(10)[labels]

return Dataset(images, labels)

train_dataset = preprocess(train_images, train_labels)

test_dataset = preprocess(test_images, test_labels)

5. 创建模型和优化器

我们现在可以创建一个神经网络模型和一个优化器。我们使用Adam优化器,它是梯度下降法的一种变种,可以在训练过程中自适应地调整学习率,加快收敛。

我们使用前面定义的常量来创建我们的神经网络和优化器。

model = Network(input_size, hidden_size, output_size)

optimizer = tf.optimizers.Adam(learning_rate)

6. 训练模型

我们现在可以训练我们的神经网络模型了。我们使用前面定义的常量来进行训练。

训练过程可能需要数分钟,具体时间取决于电脑的性能。在实际工作中,我们可以使用分布式训练等技术来加速训练过程。

train(model, train_dataset, optimizer, epochs, batch_size)

7. 测试模型

我们使用测试数据集来测试我们的模型,并计算模型的准确率。

def accuracy(model, dataset):

y_pred = np.argmax(model.forward(dataset.images), axis=1)

y_true = np.argmax(dataset.labels, axis=1)

correct = np.sum(y_pred == y_true)

return correct / dataset.num_examples

print("Test accuracy: {}".format(accuracy(model, test_dataset)))

8. 结论和展望

我们使用Python编写了一个手写数字识别的实例,并通过自己编写的神经网络模型对手写数字图片进行了识别。实验结果表明,我们的模型在MNIST数据集上取得了非常不错的准确率。

在实际工作中,我们可以通过改善模型结构、增加训练数据、使用数据增强等方法来进一步提高模型的准确率。

后端开发标签