La implementación práctica de Deep Learning Framework-4 utiliza la función de pérdida de entropía cruzada para admitir tareas de clasificación

Repositorio de código: https://github.com/brandonlyg/cute-dl

Target

  1. Aumente la función de pérdida de entropía cruzada, de modo que el marco pueda soportar el modelo de tarea de clasificación.
  2. Construya un modelo MLP y realice tareas de clasificación en el conjunto de datos mnist con una tasa de precisión del 91%.

Implementar la función de pérdida de entropía cruzada

Principios de matemática

Descomponer la función de pérdida de entropía cruzada

        La función de pérdida de entropía cruzada trata el valor de salida del modelo como una distribución de variables aleatorias discretas. Deje que la salida del modelo sea: \ (\ hat {Y} = f (X) \) , donde \ (f (X) \) representa el modelo. \ (\ hat {Y} \) es una matriz m X n, como se muestra a continuación:

\ [\ begin {bmatrix} \ hat {y} _ {11} & \ hat {y} _ {12} & ... & \ hat {y} _ {1n} \\ \ hat {y} _ {21 } & \ hat {y} _ {22} & ... & \ hat {y} _ {2n} \\ ... & ... & ... & ... \\ \ hat {y} _ {m1} & \ hat {y} _ {m2} & ... & \ hat {y} _ {mn} \ end {bmatrix} \]

        Deje que la fila i-ésima de esta matriz sea \ (\ hat {y} _i \) , que es un vector \ (\\ R ^ {1Xn} \) , y su elemento j-ésimo sea \ (\ hat {y } _ {ij} \) .
        La función de pérdida de entropía cruzada requiere que \ (\ hat {y} _i \) tenga las siguientes propiedades:

\ [\ begin {matrix} 0 <= \ hat {y} _ {ij} <= 1 & & (1) \\ \ sum_ {j = 1} ^ {n} \ hat {y} _ {ij} = 1, & n = 2,3, ... & (2) \ end {matriz} \]

        En particular, cuando n = 1, solo la primera propiedad necesita ser satisfecha. Primero consideramos el caso de n> 1, en cuyo caso n = 2 es equivalente a n = 1. En ingeniería, n = 1 puede considerarse como una optimización de n = 2.
        A veces, el modelo no garantiza que el valor de salida tenga estas propiedades, entonces la función de pérdida debe convertir \ (\ hat {y} _i \) en una columna de distribución: \ (\ hat {p} _i \) , la definición de la función de conversión Como sigue:

\ [\ begin {matrix} S_i = \ sum_ {j = 1} ^ {n} e ^ {\ hat {y} _ {ij}} \\ \ hat {p} _ {ij} = \ frac {e ^ {\ hat {y} _ {ij}}} {S_i} \ end {matrix} \]

        Aquí \ (\ hat {p} _i \) se requiere para cumplir. La función \ (e ^ {\ hat {y} _ {ij}} \) es una función monotónicamente creciente, para cualesquiera dos \ (\ hat {y} _ {ia} < \ hat {y} _ {ib} \) , Todos: \ (e ^ {\ hat {y} _ {ia}} \)\ (e ^ {\ hat {y} _ {ib}} \) , que le da: \ (\ hat { p} _ {ia} < \ hat {p} _ {ib} \) . Por lo tanto, esta función convierte el valor de salida del modelo en un valor de probabilidad, y la relación entre el tamaño de la probabilidad y el tamaño del valor de salida es la misma.
        Deje que la etiqueta de categoría de datos \ (x_i \) sea \ (y_i \)\ (\\ R ^ (1Xn) \) . Si la categoría real de \ (x_i \) es t, \ (y_i \) satisface:

\ [\ begin {matrix} y_ {ij} = 1 & {if j = t} \\ y_ {ij} = 0 & {if j ≠ t} \ end {matrix} \]

        \ (y_i \) usa codificación de un solo hot. La definición de la función de pérdida de entropía cruzada es:

\ [J_i = \ frac {1} {m} \ sum_ {j = 1} ^ {n} -y_ {ij} ln (\ hat {p} _ {ij}) \]

        Para cualquier \ (y_ {ij} \) , cualquier elemento en la función de pérdida tiene las siguientes propiedades:

\ [\ begin {matrix} -y_ {ij} ln (\ hat {p} _ {ij}) ∈ [0, ∞), y if: y_ {ij} = 1 \\ -y_ {ij} ln (\ hat {p} _ {ij}) = 0, y if: y_ {ij} = 0 \ end {matrix} \]

        Se puede ver que el término \ (y_ {ij} = 0 \) no afecta el valor de la función de pérdida, por lo que dichos términos pueden ignorarse de la función de pérdida durante el cálculo. Para otros términos de \ (y_ {ij} = 1 \) , cuando \ (\ hat {p} _ {ij} = y_ {ij} = 1 \) , la función de pérdida alcanza el valor mínimo 0.

Derivación de gradiente

        De acuerdo con la regla de la cadena, el gradiente de la función de pérdida es:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _ {ij}} = \ frac {\ partial J_i} {\ partial \ hat {p} _ {ij}} \ frac {\ partial \ hat {p} _ {ij}} {\ partial \ hat {y} _ {ij}}, \ quad (1) \]

        Entre ellos:

\ [\ frac {\ partial J_i} {\ partial \ hat {p} _ {ij}} = \ frac {1} {m} \ frac {-y_ {ij}} {\ hat {p} _ {ij} } \ quad (2) \]

\ [\ frac {\ partial \ hat {p} _ {ij}} {\ partial \ hat {y} _ {ij}} = \ frac {e ^ {\ hat {y} _ {ij}} S_i - e ^ {2 \ hat {y} _ {ij}}} {S_i ^ 2} = \ frac {\ hat {y} _ {ij}} {S_i} - [\ frac {e ^ {\ hat {y} _ {ij}}} {S_i}] ^ 2 = \ hat {p} _ {ij} - (\ hat {p} _ {ij}) ^ 2 = \ hat {p} _ {ij} (1- \ hat {p} _ {ij}) \ quad (3) \]

        Al sustituir (2), (3) en (1) se obtiene:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _ {ij}} = \ frac {1} {m} \ frac {-y_ {ij}} {\ hat {p} _ {ij} } \ hat {p} _ {ij} (1- \ hat {p} _ {ij}) = \ frac {1} {m} (y_ {ij} \ hat {p} _ {ij} -y_ {ij }) \]

        Desde cuando \ (y_ {ij} = 0 \) , el valor del gradiente es 0, por lo que esta situación se puede ignorar y el gradiente final es:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _ {ij}} = \ frac {1} {m} (\ hat {p} _ {ij} -y_ {ij}) \]

        Si el valor de salida del modelo es las columnas de distribución de una variable aleatoria, la pérdida de función se puede omitir a \ (\ hat {y} _ {ij} \) se convierte en \ (\ hat {p} _ {ij} \) paso , Esta vez \ (\ hat {y} _ {ij} = \ hat {p} _ {ij} \) , el gradiente final se convierte en:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _ {ij}} = \ frac {\ partial J_i} {\ partial \ hat {p} _ {ij}} = - \ frac {y_ { ij}} {m \ hat {y} _ {ij}} \]


Caso especial de la función de pérdida de entropía cruzada: solo dos categorías

        Ahora analicemos el caso cuando n = 1. En este momento, \ (\ hat {y} _i \)\ (\\ R ^ {1 X 1} \) puede tratarse como un escalar.
        Si el resultado del modelo no es una columna de distribución, la función de pérdida se puede descomponer en:

\ [\ begin {matrix} \ hat {p} _ {i} = \ frac {1} {1 + e ^ {- \ hat {y} _ {i}}} \\ \\ J_i = \ frac {1 } {m} [- y_iln (\ hat {p} _ {i}) - (1-y_i) ln (1- \ hat {p} _ {i})] \ end {matriz} \]

        El gradiente de la función de pérdida con respecto al valor de salida es:

\ [\ frac {\ partial J_i} {\ partial \ hat {p} _i} = \ frac {1} {m} (- \ frac {y_i} {\ hat {p} _i} + \ frac {1-y_i } {1 - \ hat {p} _i}) = \ frac {\ hat {p} _i - y_i} {m \ hat {p} _i (1- \ hat {p} _i)}, \ quad (1) \]

\ [\ frac {\ partial \ hat {p} _i} {\ partial \ hat {y} _i} = \ frac {e ^ {- \ hat {y} _ {i}}} {(1 + e ^ { - \ hat {y} _ {i}}) ^ 2} = \ frac {1} {1 + e ^ {- \ hat {y} _ {i}}} \ frac {e ^ {- \ hat {y } _ {i}}} {1 + e ^ {- \ hat {y} _ {i}}} = \ hat {p} _ {i} (1- \ hat {p} _ {i}), \ quad (2) \]

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _i} = \ frac {\ partial J_i} {\ partial \ hat {p} _i} \ frac {\ partial \ hat {p} _i} { \ parcial \ sombrero {y} _i}, \ quad (3) \]

        Sustituyendo (1), (2) en (3) da:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _i} = \ frac {\ hat {p} _i - y_i} {m \ hat {p} _i (1- \ hat {p} _i) } \ hat {p} _ {i} (1- \ hat {p} _ {i}) = \ frac {1} {m} (\ hat {p} _i - y_i) \]

        Si el valor de salida del modelo es la columna de distribución de una variable aleatoria, entonces hay:

\ [\ frac {\ partial J_i} {\ partial \ hat {y} _i} = \ frac {\ partial J_i} {\ partial \ hat {p} _i} = \ frac {\ hat {y} _i - y_i} {m \ hat {y} _i (1- \ hat {y} _i)} \]


Código de implementación

        Los códigos de implementación de estas dos funciones de pérdida de entropía cruzada están en cutedl / loss.py. El nombre general de la clase de función de pérdida de entropía cruzada es CategoricalCrossentropy, y su código de implementación principal es el siguiente:

  '''
  输入形状为(m, n)
  '''
  def __call__(self, y_true, y_pred):
      m = y_true.shape[0]
      #pdb.set_trace()
      if not self.__form_logists:
          #计算误差
          loss = (-y_true*np.log(y_pred)).sum(axis=0)/m
          #计算梯度
          self.__grad = -y_true/(m*y_pred)
          return loss.sum()

      m = y_true.shape[0]
      #转换成概率分布
      y_prob = dlmath.prob_distribution(y_pred)
      #pdb.set_trace()
      #计算误差
      loss = (-y_true*np.log(y_prob)).sum(axis=0)/m
      #计算梯度
      self.__grad  = (y_prob - y_true)/m

      return loss.sum()

        La función prob_distribution convierte la salida del modelo en una columna de distribución, y el método de implementación es el siguiente:

def prob_distribution(x):
    expval = np.exp(x)
    sum = expval.sum(axis=1).reshape(-1,1) + 1e-8

    prob_d = expval/sum

    return prob_d

        El nombre de la clase de función de pérdida de entropía cruzada de clasificación binaria es Binary Crosssentropy, y su código de implementación principal es el siguiente:

'''
输入形状为(m, 1)
'''
def __call__(self, y_true, y_pred):
    #pdb.set_trace()
    m = y_true.shape[0]

    if not self.__form_logists:
        #计算误差
        loss = (-y_true*np.log(y_pred)-(1-y_true)*np.log(1-y_pred))/m
        #计算梯度
        self.__grad = (y_pred - y_true)/(m*y_pred*(1-y_pred))
        return loss.sum()

    #转换成概率
    y_prob = dlmath.sigmoid(y_pred)
    #计算误差
    loss = (-y_true*np.log(y_prob) - (1-y_true)*np.log(1-y_prob))/m
    #计算梯度
    self.__grad = (y_prob - y_true)/m

    return loss.sum()

Verificar en el conjunto de datos MNIST

        Ahora use la tarea de clasificación MNIST para verificar la función de pérdida de entropía cruzada. El código se encuentra en el archivo examples / mlp / mnist-recognize.py. Antes de ejecutar este código, descargue el conjunto de datos MNIST original a examples / datasets / y descomprímalo. El enlace de descarga del conjunto de datos es: https://pan.baidu.com / s / 1CmYYLyLJ87M8wH2iQWrrFA, contraseña: 1rgr

        El código para entrenar el modelo es el siguiente:

'''
训练模型
'''
def fit():
    inshape = ds_train.data.shape[1]
    model = Model([
                nn.Dense(10, inshape=inshape, activation='relu')
            ])
    model.assemble()

    sess = Session(model,
            loss=losses.CategoricalCrossentropy(),
            optimizer=optimizers.Fixed(0.001)
            )

    stop_fit = session.condition_callback(lambda :sess.stop_fit(), 'val_loss', 10)

    #pdb.set_trace()
    history = sess.fit(ds_train, 20000, val_epochs=5, val_data=ds_test,
                        listeners=[
                            stop_fit,
                            session.FitListener('val_end', callback=accuracy)
                        ]
                    )

    fit_report(history, report_path+"0.png")

        Informe de ajuste:

        se puede ver que después de una hora (3699s), casi 6 millones de pasos de entrenamiento, la tasa de precisión del modelo alcanzó el 92%. El mismo modelo puede alcanzar el 91% después de diez minutos de entrenamiento en Tensorflow (versión de CPU). Esto muestra que el marco cute-dl no es un problema en términos de rendimiento de la tarea, pero la velocidad de los modelos de entrenamiento no es buena.

Resumen

        En esta etapa, el marco implementa el soporte para tareas de clasificación y verifica que el rendimiento del modelo cumple con las expectativas en el conjunto de datos MNIST. La velocidad del entrenamiento modelo no es satisfactoria.
        En la siguiente etapa, se agregará un optimizador de velocidad de aprendizaje al modelo para acelerar el entrenamiento del modelo sin perder las capacidades de generalización.

Supongo que te gusta

Origin www.cnblogs.com/brandonli/p/12745859.html
Recomendado
Clasificación