基于MNIST数据库手写数字识别

最近在研究机器学习,只看视频和教材太累,感觉有点形而上学。于是就把吴恩达教授教学视频的课后作业关于手写数字识别的作业在pytorch框架下实现了一遍。

关于手写数字的识别问题,实际上是一个传统的利用神经网络去解决问题的一个例子。初步了解pytorch之后,搭建了一个MLP网络去实现,具体步骤如下:

  1. 构建一个三层网络,确定输入层、隐藏层以及输出层维数;
  2. 前向传播,自己编写forward函数,主要就涉及一些矩阵运算;
  3. 定义loss function,这里采用交叉熵函数;
  4. 反向传播,更新权值(利用内置torch.optim.Adam函数);
  5. 训练网络并测试。

代码如下:

from argparse import Namespace
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.io as sio
import torch
import random

# Arguments
args = Namespace(
    seed=1234,
    #num_samples_per_class=500,
    dimensions=784,
    num_classes=10,
    train_size=0.75,
    test_size=0.25,
    num_hidden_units=30,
    learning_rate=4e-2,
    regularization=1e-3,
    num_epochs=200,
    #dropout_p=0.1,
)

# Set seed for reproducability
np.random.seed(args.seed)

#导入matlab文件.mat
#用'/'代替'\'避免'\'在python中被解释成转义字符而出现错误
matdata='C:/Users/HIT/Documents/MATLAB/data.mat'
data=sio.loadmat(matdata)

#转换成numpy形式
X1=np.transpose(data['image'])
X=X1[:5000,:]
y1=np.array(data['label'])
y=y1[:5000,:]

#将数据从向量转换成张量
X = torch.from_numpy(X).float()
y = torch.from_numpy(y).long()
#len默认计算行的长度
print(len(X))
print(len(y))
#X is 60000*784,每一行代表一张图片
#y is 60000*1,每一行代表图片的标签
#从0-9共10类标签
#打乱数据
shuffle_indicies = torch.LongTensor(random.sample(range(0, len(X)), len(X)))
# print(shuffle_indicies)
X = X[shuffle_indicies]
y = y[shuffle_indicies]

# Split datasets 将数据集分割成训练集和测试集
test_start_idx = int(len(X) * args.train_size)
X_train = X[:test_start_idx]
y_train1 = y[:test_start_idx]
y_train=y_train1.squeeze() #压缩多余的维度
X_test = X[test_start_idx:]
y_test1 = y[test_start_idx:]
y_test=y_test1.squeeze()
print("We have %i train samples and %i test samples." % (len(X_train), len(X_test)))

#导入pytorch
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class MLP(nn.Module):
    #初始化网络结构
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim) #first layer 计算z1=X*W1
        self.fc2 = nn.Linear(hidden_dim, output_dim) #second layer 计算z2=a_1*W2

    def init_weights(self):
        #xavier正态分布 初始化权值
        nn.init.xavier_normal_(self.fc1.weight, gain=nn.init.calculate_gain('relu'))

    #前向传播
    def forward(self, x_in, apply_softmax=False):
        a_1 = F.relu(self.fc1(x_in)) # activaton function added! a_1=f(z1)
        #a_1 = self.dropout(a_1)  #dropping some neurons
        y_pred = self.fc2(a_1) #y_pred=f(z2)

        if apply_softmax:
            y_pred = F.softmax(y_pred, dim=1) #y_pred=softmax(y_pred)
                                              #利用softmax函数将其映射到0,1之间

        return y_pred

# Initialize model
model = MLP(input_dim=args.dimensions,
            hidden_dim=args.num_hidden_units,
            output_dim=args.num_classes)
print (model.named_modules)

# Accuracy
def get_accuracy(y_pred, y_target):
    #计算出y_pred=y_target的次数
    n_correct = torch.eq(y_pred, y_target).sum().item()
    accuracy = n_correct / len(y_pred) * 100
    return accuracy

# Optimization
loss_fn = nn.CrossEntropyLoss()  #定义交叉熵作为loss函数
optimizer = optim.Adam(model.parameters(), lr=args.learning_rate,weight_decay=args.regularization)

# Training
for t in range(args.num_epochs):
    # Forward pass
    y_pred = model(X_train)

    # Accuracy
    _, predictions = y_pred.max(dim=1)
    accuracy = get_accuracy(y_pred=predictions.long(), y_target=y_train)

    # Loss
    loss = loss_fn(y_pred, y_train)

    # Verbose
    if t%20==0:
        print ("epoch: {0:02d} | loss: {1:.4f} | acc: {2:.1f}%".format(
            t, loss, accuracy))
        print(predictions)
        print(y_train)
    # Zero all gradients
    #梯度清零,防止积累导致错误
    optimizer.zero_grad()

    # Backward pass 反向传播
    loss.backward()

    # Update weights 更新权值
    optimizer.step()

# Predictions
_, pred_train = model(X_train, apply_softmax=True).max(dim=1)
_, pred_test = model(X_test, apply_softmax=True).max(dim=1)

# Train and test accuracies
train_acc = get_accuracy(y_pred=pred_train, y_target=y_train)
test_acc = get_accuracy(y_pred=pred_test, y_target=y_test)
print ("train acc: {0:.1f}%, test acc: {1:.1f}%".format(train_acc, test_acc))

网络训练之后,训练集精度能够达到98%左右,测试集精度在93%左右。虽然在程序中运用了正则化方法来解决过拟合问题,不过好像并没有得到很好的效果。后续会采用不同方法来调试模型,第一次写博客,水平有限,望大佬们不吝赐教!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于实现MNIST手写数字图像识别的问题。首先,我们需要了解MNIST数据集是什么。MNIST数据集是一个手写数字数据库,由60,000个训练图像和10,000个测试图像组成。每个图像都是28×28像素,灰度图像,表示0到9之间的数字。 为了实现MNIST手写数字图像识别,我们可以使用Python编程语言及其深度学习框架Keras。以下是实现步骤: 1. 导入MNIST数据集 我们可以使用Keras提供的mnist模块来导入MNIST数据集。首先,我们需要安装Keras:`pip install keras`。然后,通过以下代码导入MNIST数据集: ```python from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() ``` 这里,x_train和x_test是训练集和测试集中的图像数据,y_train和y_test是相应的标签。 2. 数据预处理 我们需要对数据进行预处理,以便在神经网络中使用。首先,我们将图像数据从二维数组(28×28像素)转换为一维数组(784像素)。然后,我们将像素值缩放到0到1之间。 ```python x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train.astype('float32') / 255 x_test = x_test.astype('float32') / 255 ``` 3. 构建神经网络模型 我们可以使用Keras的Sequential模型来构建神经网络模型。我们将使用两个密集层,每个层包含128个神经元,并使用ReLU激活函数。最后,我们在输出层使用softmax激活函数,以获得0到9之间每个数字的预测概率。 ```python from keras.models import Sequential from keras.layers import Dense model = Sequential() model.add(Dense(128, activation='relu', input_shape=(784,))) model.add(Dense(128, activation='relu')) model.add(Dense(10, activation='softmax')) ``` 4. 编译和训练模型 我们需要编译模型,并指定损失函数、优化器和评估指标。我们使用交叉熵损失函数、Adam优化器和准确率评估指标。 ```python model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) ``` 然后,我们可以使用训练集对模型进行训练。 ```python model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test)) ``` 5. 评估模型 最后,我们可以使用测试集评估模型的性能。 ```python score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) ``` 这将输出模型在测试集上的损失和准确率。 希望这个回答对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值