PyTorch en acción: implementación del reconocimiento de dígitos escritos a mano MNIST


Prefacio

Se puede decir que PyTorch es el más adecuado para que los principiantes aprendan entre los tres marcos principales. En comparación con otros marcos principales, la simplicidad y facilidad de uso de PyTorch lo convierten en la primera opción para los principiantes. El punto que quiero enfatizar es que el marco se puede comparar con un lenguaje de programación, que es solo una herramienta para que logremos los efectos del proyecto, es decir, las ruedas que usamos para construir automóviles. En lo que debemos concentrarnos es en comprender cómo usar Torch para implementar funciones sin preocuparnos demasiado Cómo hacer las ruedas nos llevará demasiado tiempo de aprendizaje. En el futuro, habrá una serie de artículos que explican en detalle el marco de aprendizaje profundo, pero solo más tarde nos familiarizaremos más con el conocimiento teórico y las operaciones prácticas del aprendizaje profundo antes de que podamos comenzar a aprender. En esta etapa es aprender a utilizar estas herramientas.

El contenido del aprendizaje profundo no es tan fácil de dominar: contiene muchos conocimientos teóricos matemáticos y muchos principios de fórmulas de cálculo que requieren razonamiento. Y sin una operación real, es difícil entender qué papel representa en última instancia el código que escribimos en el marco informático de la red neuronal. Sin embargo, haré todo lo posible para simplificar el conocimiento y convertirlo en contenido con el que estemos más familiarizados. Haré todo lo posible para que todos comprendan y se familiaricen con el marco de la red neuronal, para garantizar una comprensión y una deducción fluidas, y Trate de no utilizar demasiadas fórmulas matemáticas y conocimientos teóricos profesionales. Comprenda e implemente rápidamente el algoritmo en un artículo y domine este conocimiento de la manera más eficiente.


El blogger se ha centrado en el modelado de datos durante cuatro años, ha participado en docenas de modelos matemáticos, grandes y pequeños, y comprende los principios de varios modelos, el proceso de modelado de cada modelo y varios métodos de análisis de problemas. El propósito de esta columna es utilizar rápidamente varios modelos matemáticos, aprendizaje automático, aprendizaje profundo y código desde cero. Cada artículo contiene proyectos prácticos y código ejecutable. Los blogueros se mantienen al día con varias competencias digitales y analógicas. Para cada competencia digital y analógica, los blogueros escribirán las últimas ideas y códigos en esta columna, así como ideas detalladas y códigos completos. Espero que los amigos necesitados no se pierdan la columna cuidadosamente creada por el autor.

Aprendizaje rápido en un artículo: modelos de uso común en modelado matemático


1. Carga del conjunto de datos

MNIST (Instituto Nacional Modificado de Estándares y Tecnología) es un conjunto de datos de dígitos escritos a mano que se usa comúnmente para entrenar varios sistemas de procesamiento de imágenes.

Contiene una gran cantidad de imágenes de dígitos escritos a mano, estos números van del 0 al 9. Cada imagen es una imagen en escala de grises, de 28x28 píxeles de tamaño, que representa un dígito escrito a mano.

El conjunto de datos MNIST se divide en dos partes: conjunto de entrenamiento y conjunto de prueba. El conjunto de entrenamiento suele contener 60.000 imágenes y se utiliza para entrenar el modelo. El conjunto de prueba contiene 10.000 imágenes y se utiliza para evaluar el rendimiento del modelo.

El conjunto de datos MNIST es un conjunto de datos muy popular que se utiliza para probar y validar varios modelos de aprendizaje automático y aprendizaje profundo, especialmente en tareas de reconocimiento de imágenes. Puede visitar directamente el sitio web oficial para descargar o utilizar torchvision en el programa para descargar el conjunto de datos.

Sitio web oficial: LA BASE DE DATOS MNIST

Hay 4 archivos en total: conjunto de entrenamiento, etiquetas de conjunto de entrenamiento, conjunto de prueba y etiquetas de conjunto de prueba:

Nombre del archivo tamaño contenido
etiquetas-de-tren-idx1-ubyte.gz 9,681 KB 55.000 conjuntos de entrenamiento y 5.000 conjuntos de validación
etiquetas-de-tren-idx1-ubyte.gz 29KB Etiquetas correspondientes a imágenes del conjunto de entrenamiento.
t10k-imagenes-idx3-ubyte.gz 1.611 KB 10.000 equipos de prueba
t10k-etiquetas-idx1-ubyte.gz 5 kilos Etiquetas correspondientes a imágenes del conjunto de prueba.

 El programa carga el conjunto de datos MNIST:

from torch.utils.data import DataLoader
import torchvision.datasets as dsets

transform = transforms.Compose([
    transforms.Grayscale(num_output_channels=1),  # 将图像转为灰度
    transforms.ToTensor(),  # 将图像转为张量
    transforms.Normalize((0.1307,), (0.3081,))
])

#MNIST dataset
train_dataset = dsets.MNIST(root = '/ml/pymnist',  #选择数据的根目录
                            train = True,  #选择训练集
                            transform = transform,  #不考虑使用任何数据预处理
                            download = True  #从网络上下载图片
                           )
test_dataset = dsets.MNIST(root = '/ml/pymnist',#选择数据的根目录
                           train = False,#选择测试集
                           transform = transform, #不考虑使用任何数据预处理
                           download = True #从网络上下载图片
                          )
#加载数据
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size = batch_size,
                                           shuffle = True #将数据打乱
                                          )
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                           batch_size = batch_size,
                                           shuffle = True
                                         )

visualización de imagen:

import matplotlib.pyplot as plt
digit = train_dataset.train_data[0]
plt.imshow(digit,cmap=plt.cm.binary,interpolation='none')
plt.title("Labels: {}".format(train_dataset.train_labels[0]))
plt.show()

 Después de eso, debe dividir el conjunto de datos en un conjunto de entrenamiento y un conjunto de prueba. El conjunto de datos MNIST ya está listo y se puede usar directamente:

print("train_data:",train_dataset.train_data.size())
print("train_labels:",train_dataset.train_labels.size())
print("test_data:",test_dataset.test_data.size())
print("test_labels:",test_dataset.test_labels.size())

train_data: antorcha.Tamaño([60000, 28, 28]) 
train_labels: antorcha.Tamaño([60000]) 
test_data: antorcha.Tamaño([10000, 28, 28]) 
test_labels: antorcha.Tamaño([10000])

También es necesario determinar el tamaño del lote, que en el entrenamiento de redes neuronales batch_sizese refiere a la cantidad de muestras que el modelo procesa simultáneamente durante cada iteración del entrenamiento. Desempeña varios papeles importantes en el proceso de formación:

  • Acelere el proceso de capacitación : al procesar varias muestras al mismo tiempo, aprovechando las capacidades de computación paralela de las computadoras modernas, se puede acelerar el proceso de capacitación, especialmente cuando se utilizan GPU.
  • Reducir el consumo de memoria : cargar todo el conjunto de entrenamiento a la vez puede ocupar una gran cantidad de memoria, pero cargar los datos en lotes puede reducir el consumo de memoria, lo que permite el entrenamiento en un entorno con memoria limitada.
  • Mejorar la capacidad de generalización del modelo : durante el proceso de entrenamiento, el modelo ajustará los pesos en función de los datos de cada lote, en lugar de depender de todo el conjunto de entrenamiento. Esto puede mejorar la capacidad de generalización del modelo a diferentes muestras.
  • Evite caer en mínimos locales : pequeños lotes de muestras seleccionados aleatoriamente pueden ayudar al modelo a evitar caer en mínimos locales.
  • Mayor robustez del ruido : en cada iteración, el modelo solo ve una pequeña muestra, que puede considerarse como una especie de ruido aleatorio y ayuda a mejorar la robustez del modelo.
  • Aprendizaje en línea conveniente : para tareas de aprendizaje en línea, se pueden cargar nuevos lotes de datos dinámicamente sin volver a entrenar todo el modelo.

En general, elegir racionalmente el correcto batch_sizepuede hacer que el proceso de capacitación sea más eficiente y estable y mejorar la capacidad de generalización del modelo. Sin embargo, si es demasiado grande, batch_sizepuede provocar un desbordamiento de la memoria o ralentizar la velocidad de entrenamiento, y si es demasiado pequeño, puede batch_sizeprovocar dificultades en la convergencia del modelo. Por lo tanto, elegir el correcto batch_sizerequiere depuración y optimización en la práctica.

print("批次的尺寸:",train_loader.batch_size)
print("load_train_data:",train_loader.dataset.train_data.shape)
print("load_train_labels:",train_loader.dataset.train_labels.shape)

 

Tamaño de lote: 100 
load_train_data: torch.Size([60000, 28, 28]) 
load_train_labels: torch.Size([60000])

 De los resultados de salida, se puede ver que el número total de filas en el conjunto de datos original y el conjunto de datos leídos en lotes son los mismos. En la operación real, train_loader y test_loader se utilizarán como fuente de datos de entrada de la red neuronal.

2. Definir la red neuronal

En el artículo anterior, lo llevé a construir una red neuronal varias veces, preste atención a la inicialización de la red y las capas de entrada, capas ocultas y capas de salida correspondientes.

import torch.nn as nn
import torch

input_size = 784 #mnist的像素为28*28
hidden_size = 500
num_classes = 10#输出为10个类别分别对应于0~9

#创建神经网络模型
class Neural_net(nn.Module):
#初始化函数,接受自定义输入特征的维数,隐含层特征维数以及输出层特征维数
    def __init__(self,input_num,hidden_size,out_put):
        super(Neural_net,self).__init__()
        self.layer1 = nn.Linear(input_num,hidden_size) #从输入到隐藏层的线性处理
        self.layer2 = nn.Linear(hidden_size,out_put) #从隐藏层到输出层的线性处理
        
    def forward(self,x):
        x = self.layer1(x) #输入层到隐藏层的线性计算
        x = torch.relu(x) #隐藏层激活
        x = self.layer2(x) #输出层,注意,输出层直接接loss
        return x
        
net = Neural_net(input_size,hidden_size,num_classes)
print(net)
        
Neural_net ( 
  (capa1): Lineal (in_features = 784, out_features = 500, sesgo = Verdadero) 
  (capa2): Lineal (in_features = 500, out_features = 10, sesgo = Verdadero) 
)

 super(Neural_net, self).init ( ) es una forma en Python de llamar métodos o propiedades de una clase padre. Aquí, Neural_net es el nombre de clase del modelo de red neuronal que definió, que hereda la clase nn.Module, y nn.Module es la clase base utilizada para construir modelos de red neuronal en PyTorch. En otras palabras, su modelo de red neuronal heredará todas las propiedades y métodos de nn.Module, por lo que puede usar varias funciones definidas en nn.Module en la clase Neural_net, como agregar capas de red neuronal, especificar funciones de pérdida, etc.

3. Modelo de formación

Solo preste atención a la Variable, que se mencionó en el artículo anterior.

La variable es una abstracción utilizada para crear gráficos de cálculo en las primeras versiones de PyTorch (antes de la versión 0.4), contiene atributos como datos, grad y grad_fn, y se puede utilizar para crear gráficos de cálculo y calcular gradientes automáticamente durante la retropropagación. Sin embargo, a partir de la versión 0.4 de PyTorch, la variable se abandonó oficialmente y Tensor admite directamente la función de derivación automática y no es necesario crear una variable explícitamente.

Por lo tanto, Autograd es el mecanismo central de PyTorch para implementar la derivación automática, mientras que Variable es una abstracción utilizada para construir gráficos computacionales en las primeras versiones y ahora ha sido reemplazada por Tensor. Autograd rastrea automáticamente las operaciones en Tensor y calcula los gradientes cuando es necesario, lo que permite la retropropagación.

#optimization
import numpy as np
from torchvision import transforms

learning_rate = 1e-3 #学习率
num_epoches = 5
criterion =nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(),lr = learning_rate) #随机梯度下降

for epoch in range(num_epoches):
    print('current epoch = %d' % epoch)
    for i ,(images,labels) in enumerate(train_loader,0):
        images=images.view(-1,28*28)
        outputs = net(images) #将数据集传入网络做前向计算
        labels = torch.tensor(labels, dtype=torch.long)
        
        loss = criterion(outputs, labels) #计算loss
        
        optimizer.zero_grad() #在做反向传播之前先清楚下网络状态
        loss.backward() #Loss反向传播
        optimizer.step() #更新参数
        
        if i % 100 == 0:
            print('current loss = %.5f' % loss.item())
            
print('finished training')

 

época actual = 1 
pérdida actual = 0,27720 
pérdida actual = 0,23612 
pérdida actual = 0,39341 
pérdida actual = 0,24683 pérdida actual 
= 0,18913 pérdida actual 
= 0,31647 pérdida actual = 
0,28518 
pérdida actual = 0,18053 
pérdida 
actual = 0,34957 pérdida actual 
= 0. 31319 época actual = 2 
pérdidas actuales = 0,15138 
pérdida actual = 0,30887 
pérdida actual = 0,24257 
pérdida actual = 0,46326 
pérdida actual = 0,30790 pérdida actual 
= 0,17516 
pérdida actual = 0,32319 
pérdida actual = 0,32325 
pérdida actual = 0,32066 
pérdida actual = 0,24271

 4. Prueba de precisión

Después de que los pesos de cada capa se actualizan con Pérdida mediante el método de descenso de gradiente estocástico, la precisión de la clasificación digital para el conjunto de prueba:

#prediction
total = 0
correct =0 
acc_list_test = []
for images,labels in test_loader:
    images=images.view(-1,28*28)
    outputs = net(images) #将数据集传入网络做前向计算
    
    _,predicts = torch.max(outputs.data,1)
    total += labels.size(0)
    correct += (predicts == labels).sum()
    acc_list_test.append(100 * correct / total)
    
print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()

 

 

Por favor preste atención para evitar que se pierda. Si hay algún error, deje un mensaje para recibir asesoramiento. Muchas gracias.

Eso es todo por este tema. Mi nombre es fanstuck. Si tiene alguna pregunta, no dude en dejar un mensaje para discutirlo. Nos vemos en el próximo número.


Supongo que te gusta

Origin blog.csdn.net/master_hunter/article/details/132964457
Recomendado
Clasificación