Análisis en profundidad de ejemplos de redes neuronales convolucionales PyTorch, tomando el conjunto de datos MNIST como ejemplo

PyTorch crea pasos generales de red de aprendizaje profundo

  1. Cargue el conjunto de datos;
  2. Definir el modelo de estructura de la red;
  3. Definir la función de pérdida;
  4. Definir el algoritmo de optimización;
  5. Entrenamiento iterativo
  6. Verificación del equipo de prueba.
    Entre ellos, la fase de formación se divide principalmente en cuatro partes. 1: Proceso hacia adelante, calculando el resultado de entrada a salida. 2: Calcule el valor de la función de pérdida a partir del resultado y las etiquetas. 3: En el proceso hacia atrás, el gradiente de cada variable se calcula a partir de la pérdida. 4: El optimizador actualiza los parámetros según el gradiente.
    El siguiente es un análisis de caso específico:

1. Biblioteca de configuración

#配置库
import torch
from torch import nn,optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
  1. optim es el módulo optimizador, que incluye algoritmos de optimización específicos: SGD, Momentum, RMSProp, AdaGrad y Adam. Entre ellos, Momentum es un algoritmo de descenso de gradiente acelerado, y los otros tres son para mejorar la tasa de aprendizaje. Los más utilizados son: SGD y Adam.
  2. Variable es una encapsulación de tensor, que se usa para poner en el gráfico de cálculo para propagación hacia adelante, propagación hacia atrás y derivación automática Es un objeto básico muy importante. Contiene tres atributos importantes: datos, graduado, creador. Entre ellos, los datos representan el tensor en sí, grad representa el gradiente de la dirección de propagación y el creador es la referencia de función que crea esta variable, que se usa para retroceder todo el enlace de creación. Si es una Variable creada por el usuario, el creador es Ninguno, y esta Variable se llama Variable Hoja, y autograd solo asignará gradientes a esta Variable.
  3. DataLoader es Dataset es una clase de empaquetado, que se usa para empaquetar datos en la clase Dataset y luego se pasa a DataLoader, luego usamos DataLoader esta clase para operar con los datos más rápidamente.
    Específicamente, el conjunto de datos está empaquetado en un formato específico para facilitar su procesamiento y referencia.
  4. torchvision.transforms es el módulo de preprocesamiento de imágenes en pytorch, que contiene muchas funciones para transformar datos de imágenes, que son todas necesarias en el paso de lectura de datos de imágenes.
  5. Como sugiere el nombre, los conjuntos de datos son una serie de conjuntos de datos y los conjuntos de datos como MNIST se pueden cargar mediante los comandos correspondientes.

2. Configurar hiperparámetros

#配置参数
torch.manual_seed(1)
batch_size = 128    #批处理大小
learning_rate = 1e-2
num_epocher = 10    #训练次数
  1. torch.manual_seed () es establecer la semilla de número aleatorio para asegurar la repetibilidad del número de programa y facilitar las pruebas.
  2. batch_size es el tamaño del lote (tamaño del lote), es decir, la cantidad de datos procesados ​​cada vez. Número de iteraciones = número total de muestras / tamaño de lote; dentro de un cierto rango, cuanto mayor sea el tamaño del lote, menos iteraciones se requieren para ejecutar un conjunto de datos completo (una época) y más rápida es la velocidad de procesamiento de datos. Pero el aumento ciego conducirá a un mayor tiempo necesario para alcanzar cierta precisión.
  3. learning_rate es la tasa de aprendizaje. Cuanto menor sea la tasa de aprendizaje, menor será el paso de cada descenso de gradiente y se requieren más tiempos de entrenamiento para lograr la precisión objetivo; pero una tasa de aprendizaje demasiado grande hará que el descenso de gradiente no converja y no logre el propósito de aprendizaje.
  4. num_epocher es el número de veces que se entrena el conjunto de datos, es decir, el conjunto de datos se ha ejecutado varias veces.

3. Cargue el conjunto de datos

train_dataset = datasets.MNIST(	#训练集
    root='./data',
    train = True,
    transform=transforms.ToTensor(),
    download=False)

test_dataset = datasets.MNIST(
    root='./data',
    train=False,    #测试集
    transform=transforms.ToTensor())
train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle=False)
  1. Cargue el conjunto de datos de dígitos manuscritos de MNIST en conjuntos de datos, puede cargar el conjunto de datos descargado localmente. La raíz es la ubicación de almacenamiento del conjunto de datos; train indica si es un conjunto de entrenamiento; transform.ToTensor () es normalizar los datos del conjunto de datos y convertir la imagen con el valor [0,255] en los datos del tensor de [0,1.0] y normalizar La modificación puede mejorar la velocidad de convergencia del algoritmo de descenso de gradiente; la descarga representa si el conjunto de datos debe descargarse en línea, si no localmente, debe ser Verdadero.
  2. Cargue el conjunto de prueba y la configuración de los parámetros será similar al conjunto de entrenamiento.
  3. Como se mencionó en la sección anterior, DataLoader se usa para empaquetar datos y proporcionar un procesamiento rápido de datos. El parámetro de reproducción aleatoria es si se debe mezclar el orden. El conjunto de entrenamiento debe mezclar el orden de los datos para evitar el sobreajuste.

4. Definir el modelo de estructura de red convolucional (enfoque)

#定义卷积神经网络模型
class Cnn(nn.Module):
    def __init__(self,in_dim,n_class):
        super(Cnn,self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_dim,6,3,stride=1,padding=1),   #28x28
            nn.ReLU(True),
            nn.MaxPool2d(2,2),  #14x14,池化层减小尺寸
            nn.Conv2d(6,16,5,stride=1,padding=0),   #10x10x16
            nn.ReLU(True),
            nn.MaxPool2d(2,2)   #5x5x16
         )
        self.fc = nn.Sequential(
            nn.Linear(400,120), #400=5*5*16
            nn.Linear(120,84),
            nn.Linear(84,n_class)
        )
    def forward(self,x):
        out = self.conv(x)
        out = out.view(out.size(0),400)
        out = self.fc(out)
        return out

model = Cnn(1,10)   #图片大小28*28,10为数据种类
#打印模型
print(model)
  1. nn.Moudle es una clase muy importante, que incluye la definición de cada capa de la red y la definición de la función forword. Todos los modelos de estructura de red personalizados deben heredar la clase Moudle.
"""
自定义网络结构:
    需要继承nn.Module类,并实现forward方法。
    一般把网络中具有可学习参数的层放在构造函数__init__()中,
    不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)
    
    只要在nn.Module的子类中定义了forward函数,backward函数就会被自动实现,而不需要像forword那样需要重新定义。
"""
  1. El papel de la superclase es llamar a la función __init__ de cada clase base que contiene super cuando se hereda. Si no se usa super, la función __init__ de estas clases no se llamará a menos que se declare explícitamente. Y usar super puede evitar que se llame repetidamente a la clase base.
  2. La interpretación oficial de nn.sequential es un contenedor ordenado. El módulo de red neuronal se agregará al gráfico de cálculo para su ejecución en el orden del constructor entrante. Al mismo tiempo, un diccionario ordenado con módulos de red neuronal como elementos también se puede usar como entrada parámetro. El papel aquí es construir una estructura de red neuronal.
  3. nn.Conv2d es la función de capa convolucional de la red neuronal convolucional. Sus parámetros predeterminados son los siguientes:
    nn.Conv2d (self, in_channels, out_channels, kernel_size, stride = 1, padding = 0, dilation = 1, groups = 1, bias = True ))
    Explicación de parámetros en el programa:
      in_channel: número de canal de datos de entrada, número de canal de imagen RGB es 3, canal de imagen en blanco y negro número 1, conjunto de datos MNIST es imagen en blanco y negro, por lo que el parámetro es 1;
      out_channel: número de canal de datos de salida, también llamado Es el número de núcleos de convolución, que está relacionado con el número de características extraídas, aquí es 6;
      kennel_size: el tamaño del núcleo de convolución; aquí está el tamaño del núcleo de convolución es 3 * 3;
      stride: el tamaño del paso, el valor predeterminado es 1;
      padding: el número de relleno, es Mantenga el tamaño de salida sin cambios y tome 1 aquí.
    La fórmula para calcular el tamaño de salida de la capa convolucional es:

Por lo tanto, después de que la entrada de 1 × 28 × 28 pasa a través de la capa convolucional, la salida es 6 × 28 × 28 (6 es el número de canales de salida, es decir, la profundidad). El cálculo del valor de salida de la operación de convolución no se detalla aquí, como se muestra en la siguiente figura:

  1. nn.Relu es la función de activación, que tiene el efecto de reducir la cantidad de cálculo y aliviar el ajuste excesivo. La fórmula analítica es la siguiente:

  2. nn.MaxPool2d es la capa de agrupación de la red neuronal convolucional, que tiene la función de reducir el muestreo y reducir la cantidad de cálculo. Aquí se utiliza la capa de agrupación máxima, el tamaño del núcleo de convolución es 2 * 2 y el tamaño del paso es 2. El método de cálculo del tamaño de salida de la capa de agrupación es:
    W: ancho de la imagen, H: altura de la imagen, D: profundidad de la imagen (número de canales)
    F: ancho y alto del núcleo de convolución, S: longitud del paso
    . Tamaño de la imagen de salida después de la agrupación:
    W = (WF ) / S + 1
    H = (HF) / S + 1
    El número de canales de imagen (profundidad) de salida permanece sin cambios.
    Por lo tanto, después de la capa de agrupación en el programa, el tamaño de la imagen es 6 × 14 × 14, lo que muestra que la cantidad de cálculo se reduce.
    El cálculo de los valores de salida de las dos operaciones de agrupación es como se muestra en la figura siguiente. La agrupación máxima es retener la característica más grande en la ventana.

  3. Después de dos operaciones de convolución y agrupación, el tamaño de salida final de la imagen es una matriz tridimensional de 16 × 5 × 5. La siguiente es la capa completamente conectada (nn.liner). Anteriormente eran los datos de características de la estructura tridimensional, y la capa Liner los integraba.
    Cada nodo de la capa completamente conectada está conectado a todos los nodos de la capa anterior y se utiliza para integrar las características extraídas del frente. Debido a sus características totalmente conectadas, generalmente los parámetros de la capa totalmente conectada también son los más.
    En el programa, dado que se pasaron un total de 16 × 5 × 5 nodos en la sección anterior, la entrada es 400; debido a que los números escritos a mano deben dividirse en 10 categorías, el número de nodo de salida final es 10.

  4. La función de reenvío se utiliza para la propagación hacia adelante, que reenvía el flujo de datos. Una vez definida la función de avance, la función de retropropagación backward () se definirá automáticamente y no es necesario definirla explícitamente como la propagación de avance y se puede llamar directamente.

  5. model = Cnn (1,10) Pase los parámetros al modelo y asígnele un nombre.

5. Formación de modelos

#模型训练
#定义loss和optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=learning_rate)
#开始训练
for epoch in range(num_epocher):
    running_loss = 0.0
    running_acc = 0.0
    for i,data in enumerate(train_loader,1):
        img,label = data
        img = Variable(img)
        label = Variable(label)
        #前向传播
        out = model(img)
        #print(out)
        loss = criterion(out,label) #loss
        running_loss += loss.item() * label.size(0)
        #total loss ,由于loss是取batch均值的,因此,需要把batch size成回去
        _,pred = torch.max(out,1)   #预测结果
        num_correct = (pred == label).sum() #正确结果的数量
        #accuracy = (pred == label).float().mean()   #正确率
        running_acc += num_correct.item()   #正确结果的总数
        #后向传播
        optimizer.zero_grad()   #梯度清零
        loss.backward() #后向传播计算梯度
        optimizer.step()    #利用梯度更新W,b参数
    #打印一个循环后,训练集合上的loss和正确率
    print('Train{} epoch, Loss: {:.6f},Acc: {:.6f}'.format(epoch+1,running_loss / (len(train_dataset)),running_acc / (len(train_dataset))))
  1. nn.CrossEntropyLoss es la función de pérdida de entropía cruzada, que se utiliza para calcular la pérdida.
  2. La función SGD es un optimizador, cuya función principal es optimizar nuestra red neuronal para hacerla más rápida en nuestro proceso de entrenamiento y ahorrar tiempo. model.parameters () se utiliza para obtener los parámetros de nuestra red neuronal.
  3. enumerate () es una función incorporada de python, que se utiliza para combinar un objeto de datos transitable (como una lista, tupla o cadena, etc.) en una secuencia de índice y datos de lista y subíndices de datos al mismo tiempo.
    enumerate (a, start)
    a es un objeto iterable, start es el número inicial de conteo, el programa recorre el conjunto de entrenamiento, comenzando desde 1.
  4. La variable, mencionada en la primera sección, es una encapsulación de tensor, que se usa para colocar en el gráfico de cálculo para propagación hacia adelante, propagación hacia atrás y derivación automática. Aquí, img y etiqueta están encapsulados.
  5. out = model (img) es pasar datos al modelo para su propagación hacia adelante.
  6. pérdida = criterio (fuera, etiqueta) Aquí se compara el resultado del cálculo con la etiqueta para calcular la pérdida.
  7. running_loss + = loss.item () * label.size (0) Aquí, la pérdida se acumula y se deja como el promedio para calcular la pérdida de toda la época. En el caso de múltiples dimensiones, la pérdida es el valor medio de múltiples dimensiones, por lo que primero debe multiplicarse por el número de dimensiones.
  8. torch.max (a, 1) devuelve el elemento con el valor más grande en cada fila y devuelve su índice (devuelve el índice de columna del elemento más grande en esta fila), donde pred es el resultado de predicción devuelto.
  9. num_correct = (pred == label) .sum (), encuentra el número de resultados correctos (igual que los resultados predichos).
  10. running_acc + = num_correct.item () Encuentra el número total de resultados correctos.
  11. optimizer.zero_grad (), limpia el gradiente acumulado en el frente para facilitar la propagación hacia atrás en la parte posterior.
  12. loss.backward (), propagación hacia atrás.
  13. optimizer.step () usa retropropagación para actualizar los pesos internos del modelo de red, reduciendo así la pérdida del modelo.
  14. Finalmente, después de imprimir una época, la pérdida y precisión del conjunto de entrenamiento

6. La tasa de reconocimiento del modelo de prueba en el conjunto de prueba.

#模型测试
model.eval()    #需要说明是否模型测试
eval_loss = 0
eval_acc = 0
for data in test_loader:
    img,label = data
    img = Variable(img,volatile=True)   #改用with torch.no_grad()但还不会:这里的volatile在新的版本被移除了
    #volatile用于测试是否不调用backward
    #测试中不需要label= Variable...
    out = model(img)    #前向算法
    loss = criterion(out,label) #计算loss
    eval_loss += loss.item() * label.size(0)    #total loss
    _,pred = torch.max(out,1)   #预测结果
    num_correct = (pred == label).sum() #正确结果
    eval_acc += num_correct.item()  #正确结果总数

print('Test Loss:{:.6f},Acc: {:.6f}'
      .format(eval_loss/ (len(test_dataset)),eval_acc * 1.0/(len(test_dataset))))
  1. model.eval (), convierte el modelo en modo de prueba. El modelo model.eval () se usa para arreglar las capas de BN y deserción para que los parámetros de sesgo no cambien. Sin embargo, estas dos operaciones no se utilizan en este programa.
  2. La siguiente parte del procedimiento es similar al conjunto de entrenamiento, por lo que no lo repetiré.

7. Ejecutar resultados

Cnn (
(conv): Secuencial (
(0): Conv2d (1, 6, kernel_size = (3, 3), stride = (1, 1), padding = (1, 1))
(1): ReLU (inplace = Verdadero)
(2): MaxPool2d (kernel_size = 2, stride = 2, padding = 0, dilation = 1, ceil_mode = False)
(3): Conv2d (6, 16, kernel_size = (5, 5), stride = (1 , 1))
(4): ReLU (inplace = True)
(5): MaxPool2d (kernel_size = 2, stride = 2, padding = 0, dilation = 1, ceil_mode = False)
)
(fc): Sequential (
(0) : Lineal (in_features = 400, out_features = 120, bias = True)
(1): Lineal (in_features = 120, out_features = 84, bias = True)
(2): Lineal (in_features = 84, out_features = 10, bias = True) )
)
)
Época Train1, Pérdida: 2.285776, Acc:
0.221550 Época Train2, Pérdida: 1.370810, Acc: 0.636100
Época Train3, Pérdida: 0.411640, Acc: 0.878833
Época Train4, Pérdida: 0.294587, Acc: 0.912050
Época Train5, Pérdida: 0.231720, Acc:
0.930100 Época Train6, Pérdida: 0.188466, Acc:
0.942800 Época Train7, Pérdida: 0.158935, Acc: 0.952733
Época Train8, Pérdida: 0.139243, Acc: 0.958150
Época Train9, Pérdida: 0.125945, Acc:
0.961917 Época Train10, Pérdida: 0.115717, Acc: 0.965000
E: /Pycharm/project/project_pytorch/.idea/Conv_complete.py: 94: UserWarning: volatile se eliminó y ahora no tiene ningún efecto. Use en su with torch.no_grad():lugar.
img = Variable (img, volatile = True) #Cambie a con torch.no_grad () pero aún no: volatile here ha sido eliminado en la nueva versión
Test Loss: 0.101987, Acc .: 0.967800

Supongo que te gusta

Origin blog.csdn.net/weixin_45371989/article/details/103922630
Recomendado
Clasificación