Estás leyendo la publicación: Un tutorial sobre la creación de modelos de aprendizaje profundo de extremo a extremo en PyTorch
PyTorch es un marco muy poderoso para construir aprendizaje profundo. Este marco no es tan complejo de aprender en comparación con otros marcos de aprendizaje profundo debido a su forma sencilla de construir modelos. En este artículo, discutiremos cómo construir un modelo de aprendizaje profundo de extremo a extremo que puede ser útil para un practicante principiante de aprendizaje automático. A través de este tutorial, demostraremos cómo definir y usar una red neuronal convolucional (CNN) de una manera muy fácil explicando cada uno de los pasos en detalle. Los puntos principales que se tratarán en este artículo se enumeran a continuación.
Tabla de contenido
- Red neuronal convolucional (CNN)
- Implementando CNN usando Pytorch
- Preparando el conjunto de datos
- Construyendo el modelo
- Pautas a seguir durante la construcción del modelo
- Compilando el modelo
- Procedimiento de entrenamiento, prueba y evaluación
Primero hablemos de CNN y tratemos de entender cómo debería implementarse.
Red neuronal convolucional (CNN)
Las CNN son modelos de redes neuronales profundas que se diseñaron originalmente para analizar la entrada de imágenes 2D, pero ahora también pueden analizar datos 1D y 3D. El núcleo de una red neuronal convolucional puede estar compuesto por dos o más capas convolucionales, cada una de las cuales realiza una “convolución”, lo que implica multiplicar las entradas de la red neuronal por una serie de matrices diagonales nxn.
Esta multiplicación se logra, a diferencia de una red neuronal tradicional, mediante el uso de una “ventana” que atraviesa la imagen, conocida como filtro o kernel. Cada vez que el filtro pasa sobre la imagen, los pesos se multiplican por una serie de valores de entrada. Los valores de salida de la operación de convolución para cada posición de filtro (un valor para cada posición de filtro) forman una matriz bidimensional de valores de salida que representan las características extraídas de la imagen subyacente. Un “mapa de características” es el nombre dado a esta matriz de salida.
Una vez que se completa el mapa de características, cualquier valor en el mapa funcional se puede transmitir de forma no lineal a la siguiente capa convolucional (por ejemplo, a través de la activación de ReLU). Las capas totalmente conectadas reciben la salida de la secuencia de las capas convolucionales y generan la predicción final, que suele ser una etiqueta que describe la imagen.
Para resumir, el modelo CNN completo comprende dos capas, principalmente la capa convolucional y la segunda es la capa Pooling. La capa convolucional crea un mapa de características usando operaciones matemáticas como se explicó anteriormente y la capa de agrupación se usa aún más para reducir el tamaño del mapa de características. Las capas de agrupación más comunes son la agrupación máxima y promedio, que toma el valor máximo y promedio del tamaño del filtro, respectivamente (es decir, 2×2, 3×3, etc.).
Ahora, a continuación, veremos cómo podemos implementar un modelo CNN de este tipo utilizando PyTorch.
Implementando CNN usando Pytorch
PyTorch es una de las bibliotecas de aprendizaje profundo más conocidas y utilizadas, particularmente en la investigación académica. Es un marco de aprendizaje automático de código abierto que acorta el tiempo que lleva pasar de la creación de prototipos de investigación a la implementación de producción. Esta implementación se dividirá en pasos principales, como la carga de datos, la creación de modelos, el entrenamiento de modelos y las pruebas de modelos.
En esta sección, lo guiaremos a través del procedimiento paso a paso.
Ahora importará rápidamente todas las dependencias que se requieren.
import torch import torch.nn as nn import torchvision import torch.nn.function as F import torchvision.transforms as transforms import matplotlib.pyplot as plt
Preparando el conjunto de datos
Como se discutió primero, cargaremos el conjunto de datos. El conjunto de datos que estamos usando aquí es EMNIST, que es una versión extendida del conjunto de datos MNIST que contiene dígitos escritos a mano junto con letras escritas a mano en minúsculas y mayúsculas. El subconjunto de entrenamiento de este conjunto de datos contiene casi 1,20,000 imágenes de tamaño 28 x 28 píxeles y están en escala de grises. Podemos cargar este conjunto de datos como entrenar y probar especificando en la propia API.
A continuación, primero hemos definido la funcionalidad de preprocesamiento de las imágenes y las que se aplicarán en el conjunto de datos de entrenamiento y prueba al descargar. Más tarde, hemos utilizado el cargador de datos, que es útil, especialmente en estos casos en los que tenemos miles de imágenes y cargarlas todas a la vez mantendrá nuestro sistema bajo una carga tremenda. El cargador de datos hace que este conjunto de datos sea iterable y se pueda llamar de manera eficiente.
# aplicar transformación transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
]) # descargar los datos training_data = torchvision.datasets.EMNIST(root=”contents/”,download=True, transform=transform, train=True,split=”balanced”) test_data = torchvision.datasets.EMNIST(root=”contents /”,download=True, transform=transform, train=False,split=”balanced”) # construye el cargador de datos train_loader = torch.utils.data.DataLoader(dataset = training_data, batch_size = 128, shuffle = True) test_loader = torch.utils.data.DataLoader(conjunto de datos = test_data, batch_size = 128, shuffle = True)
Estas son algunas de las muestras de nuestro conjunto de datos.
Construyendo el modelo
El siguiente paso viene para la definición del modelo. Aquí definiremos nuestro modelo como definimos una clase sofisticada en python. Podemos comenzar creando una nueva clase que haga uso de PyTorch nn.Módulo clase. Esto es esencial cuando se construye una red neuronal porque nos proporciona una plétora de métodos útiles.
A continuación, se deben definir las capas de nuestra red neuronal. Esto se hace en la clase __en eso__ método. Simplemente podemos nombrar nuestras capas y asignarlas a la capa adecuada, como en este caso una capa convolucional, una capa de agrupación, una capa completamente conectada, etc.
Finalmente, en nuestra clase, debemos definir un adelante método. El objetivo de este método es especificar el orden en que las distintas capas procesan los datos de entrada. Combinadamente todo lo anterior podemos codificarlo como,
class CNNModel(nn.Module): def __init__(self): super(CNNModel, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size= 5,stride = 1) self. conv2 = nn.Conv2d(32, 64, 5, 1) self.fc = nn.Linear(64*20*20, 47) def adelante(self, x): x = F.relu(self.conv1(x) ) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 1) x = torch.flatten(x, 1) x = self.fc(x) salida = F.log_softmax(x, dim=1) devuelve la salida # iniciando el modelo modelo = CNNModel()
Pautas a seguir durante la construcción del modelo
Cuando observa la distribución de capas y los tamaños de las unidades debajo de la capa, puede pensar que podemos pasarlo arbitrariamente bien, pero ese no es el caso. Aunque también traté de acercarme de esa manera arbitraria, al final obtuve un error de coincidencia de dimensión.
Este error surge principalmente entre la conexión de nuestra capa convolucional y la capa Lineal. En PyTorch, cada capa toma la serie de argumentos obligatorios en nuestro caso como se muestra para la capa convolucional:canales_de_entrada, canales_de_salida, núcleos, y opcionalmente un paso.
No podemos configurar los canales de entrada arbitrariamente, pero según el tipo de nuestra imagen, ya sea en escala de grises o en blanco y negro, debería ser 1; de lo contrario, para la imagen RGB debería ser 3. Podemos configurar el tamaño de salida en cualquier número y deberíamos hacer esto es igual a la entrada de la siguiente capa consecutiva. Los núcleos no son más que el filtro que se utiliza para crear un mapa de funciones para una imagen dada y la zancada básicamente indica el movimiento del núcleo sobre una imagen aquí 1 significa que está dando un paso a la vez.
Entonces, de la capa lineal anterior, espere dos dimensiones esenciales, es decir, forma de entrada y salida. Cuando conectamos la capa convolucional a la capa lineal, acepta esencialmente el tamaño de nuestra imagen. Y la última capa convolucional a la que se ha cambiado la dimensión de nuestras imágenes ya no es de 28 x 28 píxeles.
Para obtener el valor adecuado de los canales de entrada de la capa lineal, el cálculo se puede realizar de la siguiente manera:
- Para la primera capa, proporcionamos una imagen de 28 x 28 después de aplicar 5 x 5, los tamaños de píxeles de convolución se reducen en 4 en cada lado, lo que hace 24 x 24 en la primera capa de salida.
- Además, en la siguiente capa, tenemos el mismo filtro de 5 x 5, esto lo convertirá en 20 x 20 más y este es el tamaño del lote de la imagen única en la segunda capa de salida.
Ahora, como comentamos, los canales de entrada para la capa lineal deben ser 64*20*20. Si desea aumentar las capas, siga la operación del kernel y obtenga el tamaño de lote adecuado para las capas completamente conectadas.
Ahora vayamos a la definición del modelo, en el método directo, hemos aplicado la función de activación a cada capa, después de eso, hemos aplicado una operación de agrupación en la que hemos usado la agrupación máxima, y después de haber aplanado las capas. Y por último, en el pase hacia adelante, hemos aplicado la función softmax que resultará ser un clasificador.
Compilando el modelo
Ahora, a continuación, compilaremos nuestro modelo, aquí definimos principalmente la función de pérdida y la función de optimización. Aquí se usa la entropía cruzada como una función de pérdida y se usa un optimizador de descenso de gradiente estocástico para reducir la pérdida en el proceso de entrenamiento.
# criterio de función de pérdida = nn.CrossEntropyLoss() # Optimizador optimizador = torch.optim.SGD(model.parameters(), lr=0.001)
Procedimiento de entrenamiento, prueba y evaluación
A continuación, hemos construido todos los procedimientos y cálculos. Ahora es el momento de entrenar el modelo anterior. Entrenar en PyTorch es un poco complicado aquí. Tenemos que acceder a cada elemento manualmente y tenemos que estar dispuestos en bucle para que sea un entrenamiento continuo. El procedimiento es el siguiente.
Comenzamos iterando a través del número de épocas en nuestros datos de entrenamiento, seguido de los lotes. Convertimos las imágenes y las etiquetas según el dispositivo que estemos usando, ya sea una GPU o una CPU. En el pase hacia adelante, usamos nuestro modelo para hacer predicciones y luego calculamos la pérdida en función de esas predicciones y nuestras etiquetas reales.
A continuación, realizamos un paso hacia atrás en el que actualizamos nuestros pesos para mejorar nuestro modelo. Luego, los gradientes se establecen en cero antes de cada actualización usando el optimizador.grado cero() función. Luego se calculan los nuevos gradientes usando el pérdida.hacia atrás() función.
Finalmente, usamos el optimizador.paso() Función para actualizar los pesos.
# traer modelo al dispositivo de trabajo model.to(device) # pérdida de entrenamiento train_loss = []
pérdidas_de_prueba =[]
def entrenar(e): #Cargar los datos para i, (imágenes, etiquetas) en enumerate(cargador_tren): # cargar datos en el dispositivo imágenes = imágenes.a(dispositivo) etiquetas = etiquetas.a(dispositivo) # Reenviar pase resultados = modelo (imágenes) pérdida = criterio (resultados, etiquetas) # Hacia atrás y optimizar Optimizer.zero_grad() Loss.Backward() Optimizer.Step() Train_loss.append(loss.item()) print(‘Epoch [{}/{}]Pérdida de tren: {:.4f}’.format(e+1, 10, loss.item()))
De manera similar, la técnica de prueba no es diferente al procedimiento de entrenamiento, con la excepción de calcular los gradientes porque no estamos actualizando ningún peso. Adjuntamos el código con antorcha.no graduado() porque no hay necesidad de calcular gradientes. Luego usamos nuestro modelo para anticipar cada lote y calcular cuántos de ellos son correctos.
def test(): test_loss = 0 with torch.no_grad(): correct = 0 total = 0 para imágenes, etiquetas en test_loader: imágenes = imágenes.to(dispositivo) etiquetas = etiquetas.to(dispositivo) salidas = modelo(imágenes) test_loss += F.nll_loss(salidas, etiquetas, size_average=False).item() _, predicho = torch.max(outputs.data, 1) total += etiquetas.tamaño(0) correcto += (previsto == etiquetas ).sum().item() test_loss /= len(test_loader.dataset) test_losses.append(test_loss) print(‘Precisión de prueba: {:4f} %, Pérdida de prueba: {:4f}’.format((100 * correcto/total),test_loss))
Podemos iniciar el entrenamiento y la prueba simultáneamente usando las dos funciones definidas anteriormente.
para i en el rango (10): tren (i) prueba ()
Esto da como resultado una precisión de prueba de alrededor del 79%. Para obtener más detalles, consulte el cuaderno.
Ultimas palabras
A través de este artículo, hemos discutido la red neuronal convolucional y la hemos implementado prácticamente usando PyTorch. Si comparamos esto con otros marcos, PyTorch está diseñado para estar más centrado en el desarrollador. Para usar PyTorch, uno debe tener una comprensión clara de la aplicación. En este caso, hemos desarrollado CNN para que podamos rastrear la operación convolucional a través de las capas. Por último, diría que, como principiante, deberíamos optar por PyTorch. Le ayudará a afinar sus conceptos mientras construye el modelo en sí.