Versión práctica de aprendizaje profundo-pytorch (2): red neuronal lineal

Referencias

1. Red neuronal lineal

  • Todo el proceso de entrenamiento de la red neuronal, que incluye: definir una arquitectura de red neuronal simple, procesamiento de datos, especificar la función de pérdida y cómo entrenar el modelo . La regresión lineal y la regresión softmax en las técnicas clásicas de aprendizaje estadístico pueden verse como redes neuronales lineales.

1.1 Regresión lineal

  • La regresión es una clase de métodos que pueden modelar la relación entre una o más variables independientes y una variable dependiente. En las ciencias naturales y sociales, la regresión se utiliza a menudo para representar la relación entre entradas y salidas.
  • La mayoría de tareas en el campo del aprendizaje automático suelen estar relacionadas con la predicción . Los problemas de regresión están involucrados cuando se quiere predecir un valor. Los ejemplos comunes incluyen: predecir precios (casas, acciones, etc.), predecir estadías hospitalarias (para pacientes hospitalizados, etc.), predecir la demanda (ventas minoristas, etc.)

1.1.1 Elementos básicos de la regresión lineal

  • La regresión lineal se basa en algunos supuestos simples.

    • Primero, supongamos que la variable independiente xxx y variable dependienteyyLa relación entre y es lineal, es decir,yyy se puede expresar comoxxsuma ponderada de elementos en x
    • En segundo lugar, normalmente se permite incluir algo de ruido en las observaciones y se supone que cualquier ruido es relativamente normal, como que el ruido sigue una distribución normal.
  • Para dar un ejemplo práctico: quiero estimar el precio de una casa (USD) en función de su tamaño (pies cuadrados) y antigüedad (años).

    • Para desarrollar un modelo que pueda predecir los precios de la vivienda, es necesario recopilar un conjunto de datos reales.
      • Este conjunto de datos incluye el precio de venta, el tamaño y la antigüedad de las casas.
      • En terminología de aprendizaje automático, este conjunto de datos se denomina conjunto de entrenamiento.
    • Cada fila de datos (como los datos correspondientes a una transacción de vivienda) se denomina muestra , que también puede denominarse punto de datos o instancia de datos.
    • Llame al objetivo que está tratando de predecir (como predecir los precios de la vivienda) etiqueta u objetivo.
    • Las variables independientes (área y edad) en las que se basa la predicción se denominan características o covariables.
Modelo lineal
  • El supuesto lineal significa que el objetivo (precio de la vivienda) se puede expresar como la suma ponderada de las características (área y antigüedad de la vivienda)
    precio = wara ⋅ área + salario ⋅ edad + b \mathrm{precio}=w_{\mathrm{área} }\cdot \mathrm{área}+w_{\mathrm{edad}}\cdot\mathrm{edad}+bprecio=wáreaárea+wedadedad+b

    • Warea w_ {área}weres un _suma salario w_ {edad}wedad _ _Llamado peso (peso), el peso determina la influencia de cada característica en el valor predicho.
    • cama y desayunob se llama sesgo (sesgo), compensación (compensación) o intercepción (intercepción). El sesgo se refiere a cuál debería ser el valor predicho cuando todas las características son 0. Sin un término de sesgo, el poder expresivo del modelo será limitado
    • La fórmula anterior es una transformación afín de las características de entrada . La transformación afín consiste en transformar linealmente las características ponderando y traduciendo a través del término de sesgo.
  • Dado un conjunto de datos, el objetivo es encontrar los pesos ww del modelo.w y sesgobbb , de modo que las predicciones hechas por el modelo coincidan aproximadamente con los precios reales de los datos. El valor predicho de la salida está determinado por la transformación afín de las características de entrada a través del modelo lineal, y latransformación afín está determinada por los pesos y sesgos seleccionados.

  • En el campo del aprendizaje automático, generalmente se utilizan conjuntos de datos de alta dimensión, cuando la entrada contiene ddCuando hay d características, el resultado de la prediccióny ^ \hat{y}y^(use el símbolo "puntiagudo" para yyestimaciónde y ) expresada como
    y ^ = w 1 x 1 + . . . + wdxd + b \hat{y}=w_1x_1+...+w_dx_d+by^=w1X1+...+wreXre+b

  • Coloque todas las características en el vector x ∈ R d {\mathbf{x}}\in\mathbb{R}^{d}XRd , y coloca todos los pesos en el vectorw ∈ R d {\mathbf{w}}\in\mathbb{R}^{d}wREn d , el modelo y ^ = w ⊤ x + b \hat{y}=\mathbf{w}^\top\mathbf{x}+b sepuede expresar de forma concisa en forma de producto escalar
    y^=w⊤x _+b

  • En la fórmula anterior, el vector x {\mathbf{x}}x corresponde a las características de una única muestra de datos. La matriz simbólicaX ∈ R n × d \mathbf{X}\in\mathbb{R}^{n\times d}XRn × d puede referirse convenientemente alnnnorte muestras. dondeX\mathbf{X}Cada fila de X es una muestra y cada columna es una característica. Para el conjunto de característicasX \mathbf{X}X , valor predichoy ^ ∈ R n \hat{\mathbf{y}}\in\mathbb{R}^{n}y^Rn se puede expresar mediante la multiplicación matriz-vector como
    y ^ = X w + b \hat{\mathbf{y}}=\mathbf{X}\mathbf{w}+by^=xw+b

  • Dadas las características de los datos de entrenamiento X \mathbf{X}X yla etiqueta conocida correspondiente yyy , el objetivo de la regresión lineal es encontrar un conjunto de vectores de pesowww y sesgobbb

    • Cuando está dado por X \mathbf{X}Cuando las nuevas características de la muestra se muestrean en la misma distribución de X , este conjunto de vectores de peso y compensaciones puede hacer que el error de la nueva etiqueta de predicción de la muestra sea lo más pequeño posible.
    • Incluso si estamos seguros de que la relación subyacente entre características y etiquetas es lineal, se agregará un término de ruido para tener en cuenta el impacto de los errores de observación.

Al principio para encontrar los mejores parámetros del modelo (parámetros del modelo) www ybbAntes de b , se necesitan dos cosas más.

  • (1) Una medida de la calidad del modelo.
  • (2) Un método que puede actualizar el modelo para mejorar la calidad de la predicción del modelo.
función de pérdida
  • Antes de considerar cómo ajustar un modelo a sus datos, necesita identificar una medida del ajuste. La función de pérdida puede cuantificar la diferencia entre el valor real del objetivo y el valor previsto . Por lo general, se elige un número no negativo como pérdida, y cuanto menor sea el valor, menor será la pérdida, y la pérdida es 0 para una predicción perfecta. La función de pérdida más utilizada en problemas de regresión es la función de error al cuadrado . cuando la muestra iiEl valor previsto de i es y ^ ( i ) \hat{y}^{(i)}y^( i ) , y su etiqueta verdadera correspondiente esy ( i ) y^{(i)}y( i ) , el error cuadrático se puede definir como la siguiente fórmula
    l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 l^{(i)}(\mathbf{ w} ,b)=\frac12\left(\hat{y}^{(i)}-y^{(i)}\right)^2yo( yo ) (w,segundo )=21(y^( yo )y( yo ) )2

  • Debido al término cuadrático en la función de error al cuadrado, el valor estimado y ^ ( i ) \hat{y}^{(i)}y^( i ) y observacióny ( i ) y^{(i)}yMayores diferencias entre ( i ) resultarán en mayores pérdidas. Para medir la calidad del modelo de escena en todo el conjunto de datos, es necesario calcular el conjunto de entrenamientonnPérdida promedio sobre n muestras (también equivalente a la suma) L
    ( w , b ) = 1 n ∑ i = 1 nl ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w ⊤ x ( i ) + b − y ( i ) ) 2 L(\mathbf{w},b)=\frac1n\sum_{i=1}^nl^{(i)}(\mathbf{w},b) =\frac1n\ suma_{i=1}^n\frac12\left(\mathbf{w}^\top\mathbf{x}^{(i)}+by^{(i)}\right)^2L ( w ,segundo )=norte1yo = 1norteyo( yo ) (w,segundo )=norte1yo = 1norte21( w⊤x _( yo )+by( yo ) )2

  • Al entrenar el modelo, espero encontrar un conjunto de parámetros ( w ∗ , b ∗ ) (\mathbf{w}^*,b^*)( w ,b ), este conjunto de parámetros puede minimizar la pérdida total
    w ∗ , b ∗ = argmin ⁡ w , b L ( w , b ) \mathbf{w}^*,b^*=\underset{\ mathbf{w}, b}{\nombredeloperador*{argmin}}L(\mathbf{w},b)w ,b=w , segundoargminL ( w ,segundo )

Solucion analitica
  • A diferencia de la mayoría de los otros modelos, la solución de la regresión lineal se puede expresar simplemente mediante una fórmula, lo que se denomina solución analítica. Primero, sesgue el bbb se fusiona con el parámetrow \mathbf{w}En w , la fusión se realiza agregando una columna a la matriz que contiene todos los parámetros. El problema de predicción es minimizar∥ y − X w ∥ 2 \|\mathbf{y}-\mathbf{X}\mathbf{w}\|^2yXw 2 . Éste tiene sólo un punto crítico en el plano de pérdidas, que corresponde a los mínimos de pérdidas para toda la región. perderá aproximadamentew \mathbf{w}La derivada de w se establece en 0 y la solución analítica
    w ∗ = ( X ⊤ X ) − 1 X ⊤ y \mathbf{w}^*=(\mathbf{X}^\top\mathbf{X})^ {-1 }\mathbf{X}^\top\mathbf{y}w=( X X)1X _ y
descenso de gradiente estocástico
  • El método de descenso de gradiente puede optimizar casi todos los modelos de aprendizaje profundo y reduce el error al actualizar continuamente los parámetros en la dirección de la función de pérdida decreciente.

  • Por lo general, cada vez que es necesario calcular una actualización, se selecciona aleatoriamente un pequeño lote de muestras, lo que se denomina descenso de gradiente estocástico de minibatch.

    • En cada iteración, primero tome una muestra aleatoria de un mini lote B \mathcal{B}B , que consta de un número fijo de muestras de entrenamiento.
    • Luego, calcule la derivada (también llamada gradiente ) de la pérdida promedio del mini lote con respecto a los parámetros del modelo.
    • Finalmente, multiplica el gradiente por un número positivo predeterminado η \etaSea η , también independiente del infinitivo
      w ← w − η ∣ B ∣ ∑ i ∈ B ∂ wl ( i ) ( w , b ) = w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w ⊤ x ( i ) + b − y ( i ) ), b ← b − η ∣ B ∣ ∑ i ∈ B ∂ bl ( i ) ( w , b ) = b − η ∣ B ∣ ∑ i ∈ B ( w ⊤ x(i ) + segundo − y(i)). \begin{aligned}\mathbf{w}&\leftarrow\mathbf{w}-\frac\eta{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\partial_\mathbf{w }l^{(i)}(\mathbf{w},b)=\mathbf{w}-\frac\eta{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\ mathbf{x}^{(i)}\left(\mathbf{w}^\top\mathbf{x}^{(i)}+by^{(i)}\right),\\b&\leftarrow b -\fraction{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\partial_bl^{(i)}(\mathbf{w},b)=b-\fraction {|\mathcal {B}|}\sum_{i\in\mathcal{B}}\left(\mathbf{w}^\top\mathbf{x}^{(i)}+por^{(i) }\right) .\end{alineado}wsegundowB hyo Bwyo( yo ) (w,segundo )=wB hyo BX( yo )( w⊤x _( yo )+by( yo ) ),bB hyo Bsegundoyo( yo ) (w,segundo )=bB hyo B( w⊤x _( yo )+by( yo ) ).
  • B \mathcal{B}B representa el número de muestras en cada minilote, que también se denominatamaño de lote. η\etaη representala tasa de aprendizaje (tasa de aprendizaje). Los valores para el tamaño del lote y la tasa de aprendizaje generalmente se especifican previamente manualmente en lugar de obtenerse mediante el entrenamiento del modelo.

    • Estos parámetros que se pueden ajustar pero no actualizar durante el entrenamiento se denominan hiperparámetros. El ajuste de hiperparámetros es el proceso de selección de hiperparámetros.
    • Los hiperparámetros generalmente se ajustan en función de los resultados de las iteraciones de entrenamiento, que se evalúan en un conjunto de datos de validación independiente.
Hacer predicciones con modelos.
  • Dado un modelo de regresión lineal "aprendido" w ^ ⊤ x + b ^ \mathbf{\hat{w}}^{\top}\mathbf{x}+\hat{b}w^⊤x _+b^ , ahora puede pasar el área de la casax 1 x_1X1y edad de la casa x 2 x_2X2para estimar el precio de una casa nueva (no incluido en los datos de formación). El proceso de estimar las características dadas de un objetivo a menudo se denomina predicción o inferencia.

1.1.2 Aceleración de la vectorización

  • Al entrenar un modelo, a menudo es deseable poder procesar un mini lote completo de muestras a la vez y, para lograrlo, es necesario vectorizar el cálculo.
  • Para ilustrar la importancia de la vectorización, considere dos métodos para sumar vectores , creando instancias de dos vectores de 10,000 dimensiones de todos los unos.
    • En un enfoque, use el bucle for de Python para iterar sobre el vector.
    • En otro enfoque, confiar en llamadas a +
    import math
    import time
    import numpy as np
    import torch
    
    n = 10000
    a = torch.ones([n])
    b = torch.ones([n])
    
    # 定义一个计时器
    class Timer:
        def __init__(self):
            self.times = []
            self.start()
        def start(self):
            self.tik = time.time()
    
        def stop(self):
            self.times.append(time.time() - self.tik)
            return self.times[-1]
    
        def avg(self):
            return sum(self.times) / len(self.times)
    
        def sum(self):
            return sum(self.times)
    
        def cumsum(self):
            return np.array(self.times).cumsum().tolist()
    
    # 使用 for 循环,每次执行一位的加法
    c = torch.zeros(n)
    timer = Timer()
    for i in range(n):
        c[i] = a[i] + b[i]
    
    # 使用重载的 + 运算符来计算按元素的和
    # 矢量化代码通常会带来数量级的加速
    timer.start()
    d = a + b
    
    print(f'{
            
            timer.stop():.5f} sec')
    
    # 输出
    '0.20727 sec'
    '0.00020 sec'
    

1.1.3 Distribución normal y pérdida cuadrática

  • La función objetivo de pérdida al cuadrado se interpreta mediante suposiciones sobre la distribución del ruido. Distribución normal (distribución normal), también conocida como distribución gaussiana (distribución gaussiana): si la variable aleatoria xxx tiene mediaμ \muμ y varianzaσ 2 \sigma^{2}pag2 (desviación estándarσ \sigmaσ ), su función de densidad de probabilidad de distribución normal es la siguiente
    p ( x ) = 1 2 π σ 2 exp ⁡ ( − 1 2 σ 2 ( x − μ ) 2 ) \begin{aligned}p(x)&=\frac1 { \sqrt{2\pi\sigma^2}}\exp\left(-\frac1{2\sigma^2}(x-\mu)^2\right)\end{alineado}p ( x )=2 p.d._ _2 1Exp( -2p _21( xmetro )2 )

  • Una razón por la que la función de pérdida de error cuadrático medio (pérdida cuadrática media para abreviar) se puede utilizar para la regresión lineal es que supone que las observaciones contienen ruido, donde el ruido sigue una distribución normal. La distribución normal del ruido es la siguiente, donde ϵ ∼ N ( 0 , σ 2 ) \epsilon\sim\mathcal{N}(0,\sigma^2)ϵnorte ( 0 ,pag2 )
    y = w ⊤ x + b + ϵ y=\mathbf{w}^\top\mathbf{x}+b+\epsilony=w⊤x _+b+ϵ

  • Por lo tanto, ahora es posible escribir para un x \mathbf{x} dadox observa unyyLa probabilidad de y
    P ( y ∣ x ) = 1 2 π σ 2 exp ⁡ ( − 1 2 σ 2 ( y − w ⊤ x − b ) 2 ) P(y\mid\mathbf{x})= \frac1{ \sqrt{2\pi\sigma^2}}\exp\left(-\frac1{2\sigma^2}(y-\mathbf{w}^\top\mathbf{x}-b)^ 2\right )P(yx )=2 p.d._ _2 1Exp( -2p _21( yw⊤x _segundo )2 )

  • Ahora, según el método de estimación de máxima verosimilitud, el parámetro w \mathbf{w}w ybbEl valor óptimo de b es el valor que maximiza la probabilidad de que todo el conjunto de datos
    P ( y ∣ X ) = ∏ i = 1 np ( y ( i ) ∣ x ( i ) ) P(\mathbf{y}\mid\ mathbf {X})=\prod_{i=1}^np(y^{(i)}|\mathbf{x}^{(i)})P(yX )=yo = 1nortep(y( yo )x( yo ) )

− log ⁡ P ( y ∣ X ) = ∑ i = 1 n 1 2 log ⁡ ( 2 π σ 2 ) + 1 2 σ 2 ( y ( i ) − w ⊤ x ( i ) − b ) 2 -\log P (\mathbf{y}\mid\mathbf{X})=\sum_{i=1}^n\frac12\log(2\pi\sigma^2)+\frac1{2\sigma^2}\left( y^{(i)}-\mathbf{w}^\top\mathbf{x}^{(i)}-b\right)^2iniciar sesiónP(yX )=yo = 1norte21log g ( 2 π σ2 )+2p _21( y( yo )w⊤x _( yo )segundo )2

import math
import numpy as np
import matplotlib.pyplot as plt

def normal(x, mu, sigma):
    p = 1 / math.sqrt(2 * math.pi * sigma**2)
    return p * np.exp(-0.5 / sigma ** 2 * (x - mu) ** 2)

x = np.arange(-7, 7, 0.01)

# 改变均值会产生沿 x 轴的偏移,增加方差将会分散分布、降低峰值
params = [(0, 1), (0, 2), (3, 1)]
plt.figure(figsize=(8, 6))
for mu, sigma in params:
    plt.plot(x, normal(x, mu, sigma), label=f'mean {
      
      mu}, std {
      
      sigma}')

plt.xlabel('x')
plt.ylabel('p(x)')
plt.legend()
plt.show()

inserte la descripción de la imagen aquí

1.1.4 De la regresión lineal a la red profunda

Diagrama de red neuronal
  • En la red neuronal que se muestra a continuación

    • La entrada es x 1 , … , xd x_{1},\ldots,x_{d}X1,,Xre, por lo que el número de entradas (o dimensiones de entidades ) en la capa de entrada es ddd
    • La salida de la red es o 1 o_1oh1, por lo que el número de salidas en la capa de salida es 1
  • Se dan todos los valores de entrada y solo hay una neurona computacional. Dado que el foco del modelo es donde ocurre el cálculo, la capa de entrada generalmente no se considera al calcular el número de capas. En otras palabras, el número de capas de la red neuronal en la siguiente figura es 1

  • Se puede considerar un modelo de regresión lineal como una red neuronal que consta de una sola neurona artificial o una red neuronal de una sola capa . Para la regresión lineal, cada entrada está conectada a cada salida (en este caso, solo hay una salida), y esta transformación (la capa de salida en la figura) se llama capa completamente conectada (laver completamente conectada) o llamada capa capa densa (laver densa)

inserte la descripción de la imagen aquí

1.2 Implementación simple de regresión lineal

1.2.1 Generar conjunto de datos

  • Genere un conjunto de datos de 1000 muestras, cada una de las cuales contiene 2 características muestreadas a partir de una distribución normal estándar. El conjunto de datos sintético es una matriz x ∈ R 1000 × 2 \mathbf{x}\in\mathbb{R}^{1000\times2}XR1000 × 2
  • Usando parámetros del modelo lineal w = [ 2 , − 3.4 ] T , b = 4.2 \mathbf{w}=[2,-3.4]^{\mathsf{T}},b=4.2w=[ 2 ,3.4 ]T ,b=4.2 y el término de ruidoϵ \epsilonϵGenerar el conjunto de datos y sus etiquetas.
    • ϵ \épsilonϵ puede considerarse como el error de observación potencial en la predicción y el etiquetado del modelo, suponiendo queϵ \epsilonϵ sigue una distribución normal con una media de 0, donde la desviación estándar se establece en 0,01
      y = X w + b + ϵ \mathbf{y}=\mathbf{X}\mathbf{w}+b+\epsilony=xw+b+ϵ
    import numpy as np
    import torch
    from torch.utils import data
    
    def synthetic_data(w, b, num_examples):
        X = torch.normal(0, 1, (num_examples, len(w)))
        y = torch.matmul(X, w) + b
        y += torch.normal(0, 0.01, y.shape)
        return X, y.reshape((-1, 1))
    
    true_w = torch.tensor([2, -3.4])
    true_b = 4.2
    features, labels = synthetic_data(true_w, true_b, 1000)
    

1.2.2 Leer conjunto de datos

  • Llame a la API existente en el marco para leer los datos. Pase funciones y etiquetas como parámetros de la API y especifique el tamaño de lote a través del iterador de datos. Además, el valor booleano is_train indica si desea que el objeto iterador de datos mezcle los datos en cada ciclo de iteración.
    def load_array(data_arrays, batch_size, is_train=True):
        dataset = data.TensorDataset(*data_arrays)
        return data.DataLoader(dataset, batch_size, shuffle=is_train)
    
    batch_size = 10
    data_iter = load_array((features, labels), batch_size)
    
    # 为了验证是否正常工作,读取并打印第一个小批量样本
    # 使用 iter 构造 Python 迭代器,并使用 next 从迭代器中获取第一项
    print(next(iter(data_iter)))
    
    # 输出
    [tensor([[ 1.0829, -0.0883],
            [ 0.0989,  0.7460],
            [ 1.0245, -0.1956],
            [-0.7932,  1.7843],
            [ 1.2336,  1.0276],
            [ 2.1166,  0.2072],
            [-0.1430,  0.4944],
            [ 0.7086,  0.3950],
            [-0.0851,  1.4635],
            [ 0.2977,  1.8625]]), 
    tensor([[ 6.6616],
            [ 1.8494],
            [ 6.9229],
            [-3.4516],
            [ 3.1747],
            [ 7.7283],
            [ 2.2302],
            [ 4.2612],
            [-0.9383],
            [-1.5352]])]
    

1.2.3 Definir el modelo

  • Para los modelos estándar de aprendizaje profundo, puede usar las capas predefinidas del marco, solo necesita concentrarse en qué capas se usan para construir el modelo y no necesita prestar atención a los detalles de implementación de las capas.
  • En PyTorch, las capas completamente conectadas se definen en la clase Linear. Vale la pena señalar que pasar dos parámetros a nn.Linear
    • El primero especifica la forma de la entidad de entrada, que es 2
    • El segundo especifica la forma de la característica de salida (escalar único), que es 1
    from torch import nn
    
    net = nn.Sequential(nn.Linear(2, 1))
    

1.2.4 Inicializar parámetros del modelo

  • Los parámetros del modelo deben inicializarse antes de usar net, como ponderaciones y sesgos en un modelo de regresión lineal . Los marcos de aprendizaje profundo suelen tener métodos predefinidos para inicializar parámetros. Aquí, se especifica que cada parámetro de peso debe muestrearse aleatoriamente a partir de una distribución normal con media 0 y desviación estándar 0,01, y el parámetro de sesgo se inicializará a cero.
    net[0].weight.data.normal_(0, 0.01)
    net[0].bias.data.fill_(0)
    

1.2.5 Definir la función de pérdida

  • El error cuadrático medio se calcula utilizando la clase MSELoss, también conocida como L 2 L_2 al cuadrado.l2norma. Por defecto devuelve la media de todas las pérdidas de muestra.
    loss = nn.MSELoss()
    

1.2.6 Definir el algoritmo de optimización.

  • El algoritmo de descenso de gradiente estocástico de mini lotes es una herramienta estándar para optimizar redes neuronales , y PyTorch implementa muchas variantes de este algoritmo en el módulo optim. Al crear una instancia de SGD, especifique los parámetros optimizados y un diccionario de hiperparámetros requeridos por el algoritmo de optimización. El descenso de gradiente estocástico por lotes pequeños solo necesita establecer el valor lr, aquí se establece en 0,03
    trainer = torch.optim.SGD(net.parameters(), lr=0.03)
    

1.2.7 Entrenamiento

  • En cada ciclo de iteración, el conjunto de datos se recorrerá por completo una vez y se obtendrá continuamente de él un pequeño lote de entradas y las etiquetas correspondientes. Para cada mini lote, realice los siguientes pasos
    • Genere predicciones y calcule la pérdida l llamando a net(X) ( paso hacia adelante )
    • Los gradientes se calculan mediante retropropagación.
    • Actualice los parámetros del modelo llamando al optimizador
  • Para medir mejor el efecto del entrenamiento, calcule la pérdida después de cada ciclo de iteración e imprímala para monitorear el proceso de entrenamiento.
    num_epochs = 3
    for epoch in range(num_epochs):
        for X, y in data_iter:
            l = loss(net(X) ,y)
            trainer.zero_grad()
            l.backward()
            trainer.step()
        l = loss(net(features), labels)
        print(f'epoch {
            
            epoch + 1}, loss {
            
            l:f}')
    
  • resumen de código
    import numpy as np
    import torch
    from torch.utils import data
    from torch import nn
    
    # 生成数据集
    def synthetic_data(w, b, num_examples):
        X = torch.normal(0, 1, (num_examples, len(w)))
        y = torch.matmul(X, w) + b
        y += torch.normal(0, 0.01, y.shape)
        return X, y.reshape((-1, 1))
    
    true_w = torch.tensor([2, -3.4])
    true_b = 4.2
    features, labels = synthetic_data(true_w, true_b, 1000)
    
    # 读取数据集
    def load_array(data_arrays, batch_size, is_train=True):
        dataset = data.TensorDataset(*data_arrays)
        return data.DataLoader(dataset, batch_size, shuffle=is_train)
    
    batch_size = 10
    data_iter = load_array((features, labels), batch_size)
    
    # 定义模型
    net = nn.Sequential(nn.Linear(2, 1))
    
    # 初始化模型参数
    net[0].weight.data.normal_(0, 0.01)
    net[0].bias.data.fill_(0)
    
    # 定义损失函数
    loss = nn.MSELoss()
    
    # 定义优化算法
    trainer = torch.optim.SGD(net.parameters(), lr=0.03)
    
    # 训练
    num_epochs = 3
    for epoch in range(num_epochs):
        for X, y in data_iter:
            l = loss(net(X) ,y)
            trainer.zero_grad()
            l.backward()
            trainer.step()
        l = loss(net(features), labels)
        print(f'epoch {
            
            epoch + 1}, loss {
            
            l:f}')
    
    w = net[0].weight.data
    print('w的估计误差:', true_w - w.reshape(true_w.shape))
    b = net[0].bias.data
    print('b的估计误差:', true_b - b)
    
    # 输出
    epoch 1, loss 0.000216
    epoch 2, loss 0.000104
    epoch 3, loss 0.000102
    w的估计误差: tensor([-0.0002,  0.0004])
    b的估计误差: tensor([0.0002])
    

1.3 regresión softmax

1.3.1 Problema de clasificación

  • Comience con un problema de clasificación de imágenes. Suponga que cada entrada es una imagen en escala de grises de 2 x 2. Cada valor de píxel se puede representar mediante un escalar y cada imagen corresponde a cuatro características x 1, x 2, x 3, x 4 x_{1},x_{2},x_{3},x_{4}X1,X2,X3,X4. Además, supongamos que cada imagen pertenece a una de las categorías "gato", "pollo" y "perro".
  • Una forma sencilla de representar datos categóricos: codificación one-hot . Una codificación one-hot es un vector que tiene tantos componentes como clases. El componente correspondiente a la categoría se establece en 1 y todos los demás componentes se establecen en 0. En este ejemplo, la etiqueta yyy será un vector tridimensional donde (1,0,0) corresponde a "gato", (0,1,0) a "pollo", (0,0,1) a "perro" y ∈ { (
    1 , 0 , 0 ) , ( 0 , 1 , 0 ) , ( 0 , 0 , 1 ) } y\in\{(1,0,0),(0,1,0),(0,0,1 ) \}y{( 1 ,0 ,0 ) ,( 0 ,1 ,0 ) ,( 0 ,0 ,1 )}

1.3.2 Arquitectura de red

  • Para estimar probabilidades condicionales para todas las clases posibles, se requiere un modelo con múltiples resultados, uno para cada clase. Para resolver problemas de clasificación con modelos lineales, se necesitan tantas funciones afines como resultados. Cada salida corresponde a su propia función afín. En este ejemplo hay 4 características y 3 posibles clases de salida, por lo que se necesitarán 12 escalares para representar los pesos ( ww con subíndicew ), 3 escalares para representar el sesgo (bbb ). A continuación se calculan tres predicciones no normalizadas (logits) para cada entrada:o 1 , o 2 y o 3 o_1,o_2\text{y}o_3oh1,oh2y o3
    o 1 = x 1 w 11 + x 2 w 12 + x 3 w 13 + x 4 w 14 + b 1 , o 2 = x 1 w 21 + x 2 w 22 + x 3 w 23 + x 4 w 24 + b 2 , o 3 = x 1 w 31 + x 2 w 32 + x 3 w 33 + x 4 w 34 + segundo 3 . \begin{aligned}o_1&=x_1w_{11}+x_2w_{12}+x_3w_{13}+x_4w_{14}+b_1,\\o_2&=x_1w_{21}+x_2w_{22}+x_3w_{23}+x_4w_{ 24}+b_2,\\o_3&=x_1w_{31}+x_2w_{32}+x_3w_{33}+x_4w_{34}+b_3.\end{aligned}oh1oh2oh3=X1w11+X2w12+X3w13+X4w14+b1,=X1w21+X2w22+X3w23+X4w24+b2,=X1w31+X2w32+X3w33+X4w34+b3.

  • Este proceso computacional se puede describir mediante un diagrama de red neuronal. Al igual que la regresión lineal, la regresión softmax también es una red neuronal de una sola capa debido al cálculo de cada salida o 1 , o 2 y o 3 o_1,o_2\text{y}o_3oh1,oh2y o3Depende de todas las entradas x 1 , x 2 , x 3 y x 4 x_{1},x_{2},x_{3}\text{y}x_{4}X1,X2,X3yx _4, por lo que la capa de salida de la regresión softmax también es una capa completamente conectada

inserte la descripción de la imagen aquí

1.3.3 Sobrecarga de parámetros de la capa completamente conectada

  • Las capas completamente conectadas están "completamente" conectadas y pueden tener muchos parámetros que se pueden aprender. En concreto, para cualquierd entradas yqqUna capa completamente conectada con q salidas, la sobrecarga del parámetro es O ( dq ) \mathcal{O}(dq)O ( re q ) . dd_las entradas d se convierten aqqEl costo de q productos se puede reducir aO ( dqn ) \mathcal{O}({\frac{dq}{n}})Oh (nortedq _) , donde el hiperparámetronnn se puede especificar de manera flexible para equilibrar el ahorro de parámetros y la efectividad del modelo en aplicaciones prácticas

1.3.4 operación softmax

  • La función softmax transforma predicciones no normalizadas en números no negativos que suman 1 manteniendo el modelo diferenciable. Para lograr esto, primero se exponencia cada predicción no normalizada, lo que garantiza que el resultado no sea negativo. Para garantizar que la suma de los valores de probabilidad del resultado final sea 1, divida cada resultado de exponenciación por su suma
    y ^ = softmax ( o ) donde y ^ j = exp ⁡ ( oj ) ∑ k exp ⁡ ( ok ) \ hat{\mathbf{y}}=\mathrm{softmax}(\mathbf{o})\quad\text{donde}\quad\hat{y}_j=\frac{\exp(o_j )}{\sum_k\ exp(o_k)}y^=softmax ( o )eny^j=kexp ( ok)exp ( oj)

  • Aunque softmax es una función no lineal, el resultado de la regresión de softmax todavía está determinado por la transformación afín de las características de entrada. Entonces la regresión softmax es un modelo lineal

1.3.5 Vectorización de muestras de mini lotes

  • Para mejorar la eficiencia computacional y aprovechar al máximo la GPU, los cálculos vectoriales generalmente se realizan en los datos del mini lote de muestras. La expresión de cálculo vectorial de la regresión softmax es
    O = XW + b , Y ^ = softmax ( O ) \begin{aligned}\mathbf{O}&=\mathbf{X}\mathbf{W}+\mathbf{b}, \\\hat{\mathbf{Y}}&=\mathrm{softmax}(\mathbf{O})\end{aligned}ohY^=XW+segundo ,=softmax ( O )

1.3.6 Función de pérdida

  • Ligeramente, básicamente la misma regresión lineal.

1.3.7 Bases de la teoría de la información

  • La teoría de la información se ocupa de codificar, decodificar, enviar y procesar información o datos de la manera más concisa posible.

  • La idea central de la teoría de la información es cuantificar el contenido de información en los datos , y este valor se llama distribución PP.Entropía de P (entropía)
    H [ P ] = ∑ j − P ( j ) log ⁡ P ( j ) H[P]=\sum_j-P(j)\log P(j)H [ P ]=jP ( j )iniciar sesiónP ( j )

1.3.8 Predicción y evaluación del modelo

  • Después de entrenar un modelo de regresión softmax, dadas las características de la muestra, se puede predecir la probabilidad de cada clase de salida. Por lo general, la clase con la probabilidad predicha más alta se utiliza como clase de salida . Una predicción es correcta si concuerda con la clase real (etiqueta). El rendimiento del modelo se evalúa mediante precisión, que es igual a la relación entre el número de predicciones correctas y el número total de predicciones.

1.4 Conjunto de datos de clasificación de imágenes

1.4.1 Leer conjunto de datos

import torch
import torchvision
from torch.utils import data
from torchvision import transforms
import matplotlib.pyplot as plt

# 通过 ToTensor 实例将图像数据从 PIL 类型变换成 32 位浮点数格式
# 并除以 255 使得所有像素的数值均在 0~1 之间
trans = transforms.ToTensor()
# root:指定数据集下载或保存的路径;train:指定加载的是训练数据集还是测试数据集
# transform:指定数据集的转换操作;download:指定是否下载数据集
mnist_train = torchvision.datasets.FashionMNIST(
    root="./data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
    root="./data", train=False, transform=trans, download=True)

# 将标签转换成对应的类别名称
def get_fashion_mnist_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    # 这是一个列表推导式
        # 1.将 labels 中的每个元素按照索引转换为对应的文本标签
        # 2.然后将这些元素组成一个新的列表并返回
    return [text_labels[int(i)] for i in labels]

def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):
    figsize = (num_cols * scale, num_rows * scale)
    # 第一个变量_是一个通用变量名,通常用于表示一个不需要使用的值
    # 第二个变量 axes 是一个包含所有子图对象的数组
    # 这里使用这种命名约定是为了表示只关心 axes 而不关心第一个返回值
    _, axes = plt.subplots(num_rows, num_cols, figsize=figsize)
    axes = axes.flatten()  # 将 axes 展平为一维数组
    # 遍历 axes 和 imgs 的元素,其中 i 为索引,ax 为当前子图,img 为当前图像
    for i, (ax, img) in enumerate(zip(axes, imgs)):
        if isinstance(img, torch.Tensor):  # img 是一个 torch.Tensor 类型
            # img 是一个张量,假设其形状为 (C, H, W),其中 C 代表通道数,H 代表高度,W 代表宽度
            # permute(1, 2, 0) 是对 img 进行维度重排操作。它将维度从 (C, H, W) 重排为 (H, W, C)
            ax.imshow(img.permute(1, 2, 0))
        else:
            ax.imshow(img) 
        ax.axis('off')  # 关闭图像的坐标轴
        if titles:
            ax.set_title(titles[i])
    plt.show()

X, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))
show_images(X, 2, 9, titles=get_fashion_mnist_labels(y))

inserte la descripción de la imagen aquí

1.4.2 Lectura de lotes pequeños

  • Para facilitar la lectura de los conjuntos de entrenamiento y prueba, utilice los iteradores de datos integrados en lugar de crearlos desde cero. En cada iteración, el cargador de datos lee cada vez un pequeño lote de datos , del tamaño de lote_size. Lectura imparcial de minilotes con iteradores de datos integrados que mezclan aleatoriamente todas las muestras
    • Cuando se trata de conjuntos de datos más grandes, alimentar la red de una sola vez no produce buenos resultados de entrenamiento. Por lo general, el número de la muestra completa se divide en varios lotes y el número de muestras en cada lote se denomina tamaño de muestra tamaño_lote
    batch_size = 256
    
    def get_dataloader_workers():
        return 4  # 使用 4 个进程来读取数据
    train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True, 
                                 num_workers=get_dataloader_workers())
    

1.4.3 Integrar todos los componentes

  • Ahora defina la función load_data_fashion_mnist para buscar y leer el conjunto de datos Fashion-MNIST. Esta función devuelve iteradores de datos para los conjuntos de entrenamiento y validación . Además, esta función también acepta un parámetro opcional de cambio de tamaño, que se utiliza para cambiar el tamaño de la imagen a otra forma.
    def load_data_fashion_mnist(batch_size, resize=None):
        # 下载 Fashion-MNIST 数据集,然后将其加载到内存中
        trans = [transforms.ToTensor()]
        if resize:
            trans.insert(0, transforms.Resize(resize))
        trans = transforms.Compose(trans)
        mnist_train = torchvision.datasets.FashionMNIST(
            root="./data", train=True, transform=trans, download=True)
        mnist_test = torchvision.datasets.FashionMNIST(
            root="./data", train=False, transform=trans, download=True)
        return (data.DataLoader(mnist_train, batch_size, shuffle=True,
                                num_workers=get_dataloader_workers()),
                data.DataLoader(mnist_test, batch_size, shuffle=False,
                                num_workers=get_dataloader_workers()))
    

1.5 Implementación concisa de la regresión softmax

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

# 设置随机种子以确保结果可重复
torch.manual_seed(42)

# 定义超参数
batch_size = 128        # 每个批次的样本数
learning_rate = 0.1     # 学习率,用于控制优化过程中参数更新的步长
num_epochs = 100        # 训练的轮数

# 加载 Fashion-MNIST 数据集
transform = transforms.Compose([
    transforms.ToTensor(),                # 将图像转换为张量
    transforms.Normalize((0.5,), (0.5,))  # 将像素值归一化到 [-1,1] 区间
])

# 加载训练集和测试集,并将数据转换为张量
train_dataset = torchvision.datasets.FashionMNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.FashionMNIST(root='./data', train=False, download=True, transform=transform)

# 创建训练集和测试集的数据加载器,用于批量获取数据
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=False)

# 定义模型
# 创建了一个名为 SoftmaxRegression 的类,继承自 nn.Module
class SoftmaxRegression(nn.Module):
    def __init__(self, input_size, num_classes):  # 构造函数 init 初始化
        super(SoftmaxRegression, self).__init__()
        # 定义了一个线性层 (nn.Linear) 作为模型的唯一层次结构
        # 输入大小为 input_size,输出大小为 num_classes
        self.linear = nn.Linear(input_size, num_classes)

    # 实现了前向传播操作,将输入数据通过线性层得到输出
    def forward(self, x):
        out = self.linear(x)
        return out

model = SoftmaxRegression(input_size=784, num_classes=10)

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()    # 用于计算多分类问题中的交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=learning_rate)  # 定义随机梯度下降优化器,用于更新模型的参数

# 训练模型
train_losses = []
test_losses = []
# 在模型训练的过程中,运行模型对全部数据完成一次前向传播和反向传播的完整过程叫做一个 epoch
# 在梯度下降的模型训练的过程中,神经网络逐渐从不拟合状态到优化拟合状态,达到最优状态之后会进入过拟合状态
# 因此 epoch 并非越大越好。数据越多样,相应 epoch 就越大
for epoch in range(num_epochs):
    train_loss = 0.0

    # 1.将模型设置为训练模式
    model.train()  
    for images, labels in train_loader:
        # 将输入数据展平
        images = images.reshape(-1, 784)

        # 前向传播、计算损失、反向传播和优化
        outputs = model(images)
        loss = criterion(outputs, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        train_loss += loss.item()

    # 2.将模型设置为评估模式(在测试集上计算损失)
    model.eval()  
    test_loss = 0.0
    correct = 0
    total = 0

    with torch.no_grad():
        for images, labels in test_loader:
            images = images.reshape(-1, 784)
            outputs = model(images)
            loss = criterion(outputs, labels)
            test_loss += loss.item()

            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    train_loss /= len(train_loader)
    test_loss /= len(test_loader)
    accuracy = 100 * correct / total

    train_losses.append(train_loss)
    test_losses.append(test_loss)

    print(f'Epoch [{
      
      epoch + 1}/{
      
      num_epochs}], Train Loss: {
      
      train_loss:.4f}, Test Loss: {
      
      test_loss:.4f}, Accuracy: {
      
      accuracy:.2f}%')

# 可视化损失
plt.plot(train_losses, label='Train Loss')
plt.plot(test_losses, label='Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
# 输出
Epoch [1/100], Train Loss: 0.6287, Test Loss: 0.5182, Accuracy: 81.96%
Epoch [2/100], Train Loss: 0.4887, Test Loss: 0.4981, Accuracy: 82.25%
Epoch [3/100], Train Loss: 0.4701, Test Loss: 0.4818, Accuracy: 82.49%
Epoch [4/100], Train Loss: 0.4554, Test Loss: 0.4719, Accuracy: 82.90%
Epoch [5/100], Train Loss: 0.4481, Test Loss: 0.4925, Accuracy: 82.57%
Epoch [6/100], Train Loss: 0.4360, Test Loss: 0.4621, Accuracy: 83.53%
Epoch [7/100], Train Loss: 0.4316, Test Loss: 0.4662, Accuracy: 83.53%
Epoch [8/100], Train Loss: 0.4293, Test Loss: 0.4543, Accuracy: 83.80%
Epoch [9/100], Train Loss: 0.4289, Test Loss: 0.5460, Accuracy: 81.09%
...

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_42994487/article/details/132341723
Recomendado
Clasificación