Reconocimiento de dígitos escritos a mano MNIST: de dos categorías a diez categorías

Cómo cambiar un modelo de clasificación binaria a un modelo de clasificación múltiple

En este caso, se utiliza el marco de aprendizaje profundo MindSpore.Con sus módulos de paquete amigables, definición de estructura de modelo, definición de función de pérdida, implementación de descenso de gradiente y otros procesos, el entrenamiento de modelo se puede realizar con llamadas de función simples, lo que mejora en gran medida la eficiencia del modelo. desarrollo eficiencia

1. Cargue el conjunto de datos

        Cargue el conjunto de datos completo de diez categorías 

import os
import numpy as np

import moxing as mox
import mindspore.dataset as ds

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))
    
# 读取完整训练样本和测试样本
mnist_ds_train = ds.MnistDataset(os.path.join(datasets_dir, "MNIST_Data/train"))
mnist_ds_test = ds.MnistDataset(os.path.join(datasets_dir, "MNIST_Data/test"))
train_len = mnist_ds_train.get_dataset_size()
test_len = mnist_ds_test.get_dataset_size()
print('训练集规模:', train_len, ',测试集规模:', test_len)

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

        ver 10 muestras

from PIL import Image
items_train = mnist_ds_train.create_dict_iterator(output_numpy=True)

train_data = np.array([i for i in items_train])
images_train = np.array([i["image"] for i in train_data])
labels_train = np.array([i["label"] for i in train_data])

batch_size = 10  # 查看10个样本
batch_label = [lab for lab in labels_train[:10]]
print(batch_label)
batch_img = images_train[0].reshape(28, 28)
for i in range(1, batch_size):
    batch_img = np.hstack((batch_img, images_train[i].reshape(28, 28)))  # 将一批图片水平拼接起来,方便下一步进行显示
Image.fromarray(batch_img)
[0, 2, 2, 7, 8, 4, 9, 1, 8, 8]

 2. Procesar el conjunto de datos

        Los conjuntos de datos son muy importantes para el entrenamiento. Un buen conjunto de datos puede mejorar efectivamente la precisión y la eficiencia del entrenamiento. Antes de usar el conjunto de datos, generalmente se realiza algún procesamiento en el conjunto de datos.

Realizar operaciones de aumento de datos

import mindspore.dataset.vision.c_transforms as CV
import mindspore.dataset.transforms.c_transforms as C
from mindspore.dataset.vision import Inter
from mindspore import dtype as mstype

num_parallel_workers = 1
resize_height, resize_width = 28, 28

# according to the parameters, generate the corresponding data enhancement method
resize_op = CV.Resize((resize_height, resize_width), interpolation=Inter.LINEAR)  # 对图像数据像素进行缩放
type_cast_op = C.TypeCast(mstype.int32)  # 将数据类型转化为int32。
hwc2chw_op = CV.HWC2CHW()  # 对图像数据张量进行变换,张量形式由高x宽x通道(HWC)变为通道x高x宽(CHW),方便进行数据训练。

# using map to apply operations to a dataset
mnist_ds_train = mnist_ds_train.map(operations=resize_op, input_columns="image", num_parallel_workers=num_parallel_workers)
mnist_ds_train = mnist_ds_train.map(operations=type_cast_op, input_columns="label", num_parallel_workers=num_parallel_workers)
mnist_ds_train = mnist_ds_train.map(operations=hwc2chw_op, input_columns="image", num_parallel_workers=num_parallel_workers)

buffer_size = 10000
mnist_ds_train = mnist_ds_train.shuffle(buffer_size=buffer_size)  # 打乱训练集的顺序

Realizar la normalización de datos

        Estandarice y normalice los datos de la imagen para que el valor de cada píxel esté en el rango de (0,1), lo que puede mejorar la eficiencia del entrenamiento.

rescale = 1.0 / 255.0
shift = 0.0

rescale_nml = 1 / 0.3081
shift_nml = -1 * 0.1307 / 0.3081

rescale_op = CV.Rescale(rescale, shift) 
mnist_ds_train = mnist_ds_train.map(operations=rescale_op, input_columns="image", num_parallel_workers=num_parallel_workers)

rescale_nml_op = CV.Rescale(rescale_nml, shift_nml)
mnist_ds_train = mnist_ds_train.map(operations=rescale_nml_op, input_columns="image", num_parallel_workers=num_parallel_workers)

mnist_ds_train = mnist_ds_train.batch(60000, drop_remainder=True)  # 对数据集进行分批,此处加载完整的训练集

3. Encapsular en una función

        En este punto, hemos completado la preparación de los datos de entrenamiento, y las operaciones anteriores se pueden encapsular en la función load_data_all y la función process_dataset, para que puedan usarse nuevamente más tarde.

Definir operaciones de procesamiento de datos.

Defina una función process_dataset para realizar operaciones de mejora y procesamiento de datos:

  • Defina algunos parámetros necesarios para el aumento y procesamiento de datos.

  • De acuerdo con los parámetros, generar la operación de aumento de datos correspondiente.

  • Aplique operaciones de datos a conjuntos de datos usando la función de mapeo de mapas.

  • Procese el conjunto de datos generado. 

%%writefile ../datasets/MNIST_Data/process_dataset.py
def process_dataset(mnist_ds, batch_size=32, resize= 28, repeat_size=1,
                   num_parallel_workers=1):
    """
    process_dataset for train or test

    Args:
        mnist_ds (str): MnistData path
        batch_size (int): The number of data records in each group
        resize (int): Scale image data pixels
        repeat_size (int): The number of replicated data records
        num_parallel_workers (int): The number of parallel workers
    """

    import mindspore.dataset.vision.c_transforms as CV
    import mindspore.dataset.transforms.c_transforms as C
    from mindspore.dataset.vision import Inter
    from mindspore import dtype as mstype
    
    # define some parameters needed for data enhancement and rough justification
    resize_height, resize_width = resize, resize
    rescale = 1.0 / 255.0
    shift = 0.0
    rescale_nml = 1 / 0.3081
    shift_nml = -1 * 0.1307 / 0.3081

    # according to the parameters, generate the corresponding data enhancement method
    resize_op = CV.Resize((resize_height, resize_width), interpolation=Inter.LINEAR)
    rescale_nml_op = CV.Rescale(rescale_nml, shift_nml)
    rescale_op = CV.Rescale(rescale, shift)
    hwc2chw_op = CV.HWC2CHW()
    type_cast_op = C.TypeCast(mstype.int32)
    c_trans = [resize_op, rescale_op, rescale_nml_op, hwc2chw_op]

    # using map to apply operations to a dataset
    mnist_ds = mnist_ds.map(operations=type_cast_op, input_columns="label", num_parallel_workers=num_parallel_workers)
    mnist_ds = mnist_ds.map(operations=c_trans, input_columns="image", num_parallel_workers=num_parallel_workers)

    # process the generated dataset
    buffer_size = 10000
    mnist_ds = mnist_ds.shuffle(buffer_size=buffer_size)
    mnist_ds = mnist_ds.batch(batch_size, drop_remainder=True)
    mnist_ds = mnist_ds.repeat(repeat_size)

    return mnist_ds

Definir la función de carga de datos 

%%writefile ../datasets/MNIST_Data/load_data_all.py
def load_data_all(datasets_dir):
    import os
    if not os.path.exists(datasets_dir):
        os.makedirs(datasets_dir)
    import moxing as mox
    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))
    
    # 读取完整训练样本和测试样本
    import mindspore.dataset as ds
    datasets_dir = '../datasets'
    mnist_ds_train = ds.MnistDataset(os.path.join(datasets_dir, "MNIST_Data/train"))
    mnist_ds_test = ds.MnistDataset(os.path.join(datasets_dir, "MNIST_Data/test"))
    train_len = mnist_ds_train.get_dataset_size()
    test_len = mnist_ds_test.get_dataset_size()
    print('训练集规模:', train_len, ',测试集规模:', test_len)
    
    return mnist_ds_train, mnist_ds_test, train_len, test_len

4. Cargue el conjunto de prueba procesado

import os, sys 
sys.path.insert(0, os.path.join(os.getcwd(), '../datasets/MNIST_Data'))
from process_dataset import process_dataset
mnist_ds_test = process_dataset(mnist_ds_test, batch_size= 10000)

5. Definir la estructura de la red y la función de evaluación 

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

class Network(nn.Cell):
    def __init__(self, num_of_weights):
        super(Network, self).__init__()
        self.fc = nn.Dense(in_channels=num_of_weights, out_channels=10, weight_init=Normal(0.02))  # 定义一个全连接层
        self.nonlinearity = nn.Sigmoid()
        self.flatten = nn.Flatten()
    
    def construct(self, x):  # 加权求和单元和非线性函数单元通过定义计算过程来实现
        x = self.flatten(x)
        z = self.fc(x)
        pred_y = self.nonlinearity(z)
        return pred_y
    
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

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

# 损失函数
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)

7. Implementar la función de formación 

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))

8. Configurar la información de ejecución

        Antes de la capacitación formal, use context.set_context para configurar la información necesaria para la ejecución, como el modo de ejecución, la información de back-end, el hardware y otra información.        

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

 9. 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.2832, tain_acc: 0.1698, test_acc: 0.1626 

época: 10/100, train_losses: 2.0465, tain_acc : 0.6343, test_acc: 0.6017 

época: 20/100, train_losses: 1.8368, tain_acc: 0.7918, test_acc: 0.7812 época: 30/100, train_losses: 1.7602, tain_acc: 0.8138, test_acc: 0. 

8017 

época: 40/100, tren_pérdidas: 1.7245, tain_acc: 0.8238, test_acc: 0.7972 

época: 50/100, train_losses: 1.7051, tain_acc: 0.8337, test_acc: 0.8044 época: 60/100, train_losses: 1.6922, tain_acc: 0.8403, test_acc : 0.8047 época: 

70/100 

, tren_pérdidas: 1.6827 , tain_acc: 0.8454, test_acc: 0.8033 

época: 80/100, train_losses: 1.6752, tain_acc: 0.8501, test_acc: 0.8051

época: 90/100, train_losses: 1,6689, tain_acc: 0,8536, test_acc: 0,8049 

época: 100/100, train_losses: 1,6635, tain_acc: 0,8569, test_acc: 0,8037 

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

Tiempo total de entrenamiento: 430,7 s

Hasta ahora, con una pequeña cantidad de modificación del código basada en la clasificación binaria de dígitos escritos a mano, el reconocimiento de diez clases de dígitos escritos a mano se ha realizado rápidamente.

El proceso de modificación es muy simple, pero como se puede ver en los resultados anteriores, el modelo entrenó durante 100 épocas y solo alcanzó un 80 % de precisión en la tarea de reconocimiento de dígitos escritos a mano, mientras que en la sección anterior, la tarea de dos categorías En la práctica , el modelo entrenado durante 50 épocas logró una tasa de precisión del 99 %, lo que indica que en un modelo simple como un perceptrón, el reconocimiento de dígitos escritos a mano es más difícil que la clasificación binaria.

Supongo que te gusta

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