Reconocimiento de dígitos escritos a mano MNIST: de perceptrón a red neuronal convolucional

El método de cambiar la estructura de la red modelo, el método de construcción de la red neuronal convolucional.

        En la sección anterior, se usó un modelo de perceptrón con diez nodos de salida para realizar el reconocimiento de dígitos escritos a mano, pero después de entrenar durante 100 épocas, solo alcanzó una tasa de precisión de 0,8037. Si intenta ajustar max_epochs, función de pérdida, método de descenso de gradiente o tasa de aprendizaje, encontrará que la tasa de precisión sigue siendo difícil de subir. Para usar un dicho común, significa que la lógica subyacente permanece sin cambios, y solo se hacen algunos esfuerzos superficiales, y siempre es difícil hacer una mejora importante. En este caso, puede ser posible considerar reemplazar la lógica subyacente del modelo: la estructura de la red.

Este caso se implementará utilizando CNN.

1. Cargue y procese el conjunto de datos

        Reutilice la función load_data_all y la función process_dataset guardadas en la sección anterior para cargar y procesar la cantidad total de conjuntos de datos de reconocimiento de dígitos escritos a mano.

import os
import sys
import moxing as mox

datasets_dir = '../datasets'
if not os.path.exists(datasets_dir):
    os.makedirs(datasets_dir)
    
if not os.path.exists(os.path.join(datasets_dir, 'MNIST_Data.zip')):
    mox.file.copy('obs://modelarts-labs-bj4-v2/course/hwc_edu/python_module_framework/datasets/mindspore_data/MNIST_Data.zip', 
                  os.path.join(datasets_dir, 'MNIST_Data.zip'))
    os.system('cd %s; unzip MNIST_Data.zip' % (datasets_dir))
    
sys.path.insert(0, os.path.join(os.getcwd(), '../datasets/MNIST_Data'))
from load_data_all import load_data_all
from process_dataset import process_dataset

mnist_ds_train, mnist_ds_test, train_len, test_len = load_data_all(datasets_dir)  # 加载数据集
mnist_ds_train = process_dataset(mnist_ds_train, batch_size= 60000)  # 处理训练集
mnist_ds_test = process_dataset(mnist_ds_test, batch_size= 10000)  # 处理测试集

Tamaño del conjunto de entrenamiento: 60000, tamaño del conjunto de prueba: 10000 

2. Construya la red CNN y la función de evaluación

        La función de evaluación reutiliza directamente el código en la sección anterior, y la parte de la estructura de la red debe ajustarse en gran medida. El código es el siguiente. Consulte los comentarios del código para conocer el significado específico.

import mindspore
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore.common.initializer import Normal

class Network(nn.Cell):
    """
    该网络只有三层网络,分别是卷积层1、卷积层2和全连接层1,ReLU和MaxPool2d由于不带参数,所以不计入网络层数
    """
    def __init__(self, num_of_weights):
        super(Network, self).__init__()
        
        # Convolution 1
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, 
                               kernel_size=5, pad_mode='valid', 
                               stride=1, padding=0)  # 卷积层1,输入为1个通道,输出为16个通道,卷积核大小为5,滑动步长为1,不做边缘填充
     
        # Convolution 2
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, 
                               kernel_size=5, pad_mode='valid', 
                               stride=1, padding=0)  # 卷积层2,输入为16个通道,输出为32个通道,卷积核大小为5,滑动步长为1,不做边缘填充
        
        # Fully connected 
        self.fc = nn.Dense(32 * 4 * 4, 10, weight_init= Normal(0.02))  # 全连接层1,输入维度为32*4*4,输出维度为10
        
        self.relu = nn.ReLU()  # 激活层,使用卷积网络中最常用的ReLU激活函数
        self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)  # 最大池化层
        self.flatten = nn.Flatten()
    
    def construct(self, x):
        """
        前向传播函数
        """
        # Convolution 1
        out = self.conv1(x)  # 卷积
        out = self.relu(out)  # 激活
        out = self.maxpool(out)  # 池化
        
        # Convolution 2 
        out = self.conv2(out)  # 卷积
        out = self.relu(out)  # 激活
        out = self.maxpool(out)  # 池化
        
        # Fully connected 1
        # out = out.view(out.size(0), -1)  # 输入到全连接层之前需要将32个4*4大小的特性矩阵拉成一个一维向量
        out = self.flatten(out)
        out = self.fc(out)  # 计算全连接层
        
        return out
        
def evaluate(pred_y, true_y): 
    pred_labels = ops.Argmax(output_type=mindspore.int32)(pred_y)
    correct_num = (pred_labels == true_y).asnumpy().sum().item()
    return correct_num

3. Definir la función de pérdida de entropía cruzada y el optimizador

        Reutilizar la sección anterior

# 损失函数
net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')

# 创建网络
network = Network(28*28)  
lr = 0.01
momentum = 0.9

# 优化器
net_opt = nn.Momentum(network.trainable_params(), lr, momentum)

4. Implementar la función de formación

        Reutilizar la sección anterior

def train(network, mnist_ds_train, max_epochs= 50):
    net = WithLossCell(network, net_loss)
    net = TrainOneStepCell(net, net_opt)
    network.set_train()
    for epoch in range(1, max_epochs + 1):
        train_correct_num = 0.0
        test_correct_num = 0.0
        for inputs_train in mnist_ds_train:
            output = net(*inputs_train)
            train_x = inputs_train[0]
            train_y = inputs_train[1]
            pred_y_train = network.construct(train_x)  # 前向传播
            train_correct_num += evaluate(pred_y_train, train_y)
        train_acc = float(train_correct_num) / train_len

        for inputs_test in mnist_ds_test:
            test_x = inputs_test[0]
            test_y = inputs_test[1]
            pred_y_test = network.construct(test_x)
            test_correct_num += evaluate(pred_y_test, test_y)
        test_acc = float(test_correct_num) / test_len
        if (epoch == 1) or (epoch % 10 == 0):
            print("epoch: {0}/{1}, train_losses: {2:.4f}, tain_acc: {3:.4f}, test_acc: {4:.4f}".format(epoch, max_epochs, output.asnumpy(), train_acc, test_acc, cflush=True))

5. Configurar la información de ejecución

        La especificación de hardware aquí es GPU

from mindspore import context
context.set_context(mode=context.GRAPH_MODE, device_target="GPU")  # 当选择GPU时mindspore规格也需要切换到GPU

6. Empieza a entrenar

import time
from mindspore.nn import WithLossCell, TrainOneStepCell

max_epochs = 100
start_time = time.time()
print("*"*10 + "开始训练" + "*"*10)
train(network, mnist_ds_train, max_epochs= max_epochs)
print("*"*10 + "训练完成" + "*"*10)
cost_time = round(time.time() - start_time, 1)
print("训练总耗时: %.1f s" % cost_time)
**********开始训练*********** 

época: 1/100, train_losses: 2.3024, tain_acc: 0.1307, test_acc: 0.1312 

época: 10/100, train_losses: 2.3004, tain_acc : 0.1986, test_acc: 0.1980 

época: 20/100, train_losses: 2.2937, tain_acc: 0.3035, test_acc: 0.3098 época: 30/100, train_losses: 2.2683, tain_acc: 0.3669, test_acc: 0. 3754 

época 

: 40/100, tren_pérdidas: 2.1102, tain_acc: 0.4212, test_acc: 0.4290 

época: 50/100, train_losses: 1.0519, tain_acc: 0.7415, test_acc: 0.7551 época: 60/100, train_losses: 1.3377, tain_acc: 0.7131, test_acc : 0.7190 época: 

70/100 

, tren_pérdidas: 0.9068 , tain_acc: 0.7817, test_acc: 0.7888 

época: 80/100, train_losses: 0.4193, tain_acc: 0.8732, test_acc: 0.8843

epoch: 90/100, train_losses: 0.3339, tain_acc: 0.9000, test_acc: 0.9069 

epoch: 100/100, train_losses: 0.2796, tain_acc: 0.9177, test_acc: 0.9219 

***********entrenamiento completo*** *** **** 

Tiempo total de entrenamiento: 261,2 s

Como se puede ver en el resultado anterior, al usar la red lenet para entrenar el mismo lote, la tasa de precisión alcanzó el 92 %, lo que se ha mejorado considerablemente. 

Supongo que te gusta

Origin blog.csdn.net/m0_54776464/article/details/126035250
Recomendado
Clasificación