La vecindad de clase de un conjunto de datos se puede aprender utilizando la pérdida suave del vecino más cercano
En este artículo, analizamos cómo implementar la pérdida suave del vecino más cercano de la que también hablamos. aquí.
REl aprendizaje de representaciones es la tarea de aprender las características más destacadas de un conjunto de datos determinado mediante una red neuronal profunda. Suele ser una tarea implícita que se realiza en un paradigma de aprendizaje supervisado y es un factor crucial en el éxito del aprendizaje profundo (Krizhevsky y otros, 2012; He et al., 2016; Simonyan et al., 2014). En otras palabras, el aprendizaje de representación automatiza el proceso de extracción de características. Con esto, podemos utilizar las representaciones aprendidas para tareas posteriores como clasificación, regresión y síntesis.
También podemos influir en cómo se forman las representaciones aprendidas para atender casos de uso específicos. En el caso de la clasificación, las representaciones están preparadas para tener puntos de datos de la misma clase para agruparse, mientras que para la generación (por ejemplo, en GAN), las representaciones están preparadas para tener puntos de datos reales que se agrupan con los sintetizados.
En el mismo sentido, hemos disfrutado del uso del análisis de componentes principales (PCA) para codificar características para tareas posteriores. Sin embargo, no tenemos ninguna información de clase o etiqueta en las representaciones codificadas en PCA, por lo que el rendimiento en las tareas posteriores puede mejorarse aún más. Podemos mejorar las representaciones codificadas aproximando la información de clase o etiqueta que contiene aprendiendo la estructura de vecindad del conjunto de datos, es decir, qué características están agrupadas, y dichos grupos implicarían que las características pertenecen a la misma clase según el supuesto de agrupación en la literatura de aprendizaje semi-supervisado (Chapelle et al., 2009).
Para integrar la estructura de vecindad en las representaciones, se han introducido múltiples técnicas de aprendizaje, como incrustaciones localmente lineales o LLE (Roweis y Saúl, 2000), análisis de componentes vecinales o NCA (Hinton y otros, 2004), y la incrustación de vecinos t-stocásticos o t-SNE (Maaten y Hinton, 2008).
Sin embargo, las múltiples técnicas de aprendizaje antes mencionadas tienen sus propios inconvenientes. Por ejemplo, tanto LLE como NCA codifican incorporaciones lineales en lugar de incorporaciones no lineales. Mientras tanto, las incorporaciones de t-SNE dan como resultado diferentes estructuras según los hiperparámetros utilizados.
Para evitar tales inconvenientes, podemos utilizar un algoritmo NCA mejorado que es el pérdida suave del vecino más cercano o SNNL (Salakhutdinov y Hinton, 2007; Frosst et al., 2019). El SNNL mejora el algoritmo NCA al introducir no linealidad y se calcula para cada capa oculta de una red neuronal en lugar de únicamente en la última capa de codificación. Esta función de pérdida se utiliza para optimizar la enredo de puntos en un conjunto de datos.
En este contexto, enredo se define como qué tan cerca se comparan entre sí los puntos de datos de clase similar con los puntos de datos de clase diferente. Un entrelazamiento bajo significa que los puntos de datos de clase similar están mucho más cerca entre sí que los puntos de datos de clase diferente (ver Figura 1). Tener un conjunto de puntos de datos de este tipo hará que las tareas posteriores sean mucho más fáciles de realizar con un rendimiento aún mejor. Frost y cols. (2019) ampliaron el objetivo SNNL introduciendo un factor de temperatura t. Dándonos así la siguiente como función de pérdida final,
dónde d es una métrica de distancia en entidades de entrada sin procesar o representaciones de capas ocultas de una red neuronal, y t es el factor de temperatura que es directamente proporcional a las distancias entre los puntos de datos en una capa oculta. Para esta implementación, utilizamos la distancia del coseno como nuestra métrica de distancia para cálculos más estables.
El propósito de este artículo es ayudar a los lectores a comprender e implementar la pérdida suave del vecino más cercano, por lo que analizaremos la función de pérdida para comprenderla mejor.
Métrica de distancia
Lo primero que debemos calcular son las distancias entre los puntos de datos, que son las características de entrada sin procesar o las representaciones de capas ocultas de la red.
Para nuestra implementación, utilizamos la métrica de distancia del coseno (Figura 3) para cálculos más estables. Por el momento, ignoremos los subconjuntos denotados yo y I en la figura anterior, y centrémonos en calcular la distancia del coseno entre nuestros puntos de datos de entrada. Esto lo logramos a través del siguiente código PyTorch:
normalized_a = torch.nn.functional.normalize(features, dim=1, p=2)
normalized_b = torch.nn.functional.normalize(features, dim=1, p=2)
normalized_b = torch.conj(normalized_b).T
product = torch.matmul(normalized_a, normalized_b)
distance_matrix = torch.sub(torch.tensor(1.0), product)
En el fragmento de código anterior, primero normalizamos las características de entrada en las líneas 1 y 2 usando la norma euclidiana. Luego, en la línea 3, obtenemos la transpuesta conjugada del segundo conjunto de características de entrada normalizadas. Calculamos la transpuesta conjugada a cuenta para vectores complejos. En las líneas 4 y 5, calculamos la similitud del coseno y la distancia de las características de entrada.
Concretamente, considere el siguiente conjunto de características,
tensor((( 1.0999, -0.9438, 0.7996, -0.4247),
( 1.2150, -0.2953, 0.0417, -1.2913),
( 1.3218, 0.4214, -0.1541, 0.0961),
(-0.7253, 1.1685, -0.1070, 1.3683)))
Usando la métrica de distancia que definimos anteriormente, obtenemos la siguiente matriz de distancia,
tensor((( 0.0000e+00, 2.8502e-01, 6.2687e-01, 1.7732e+00),
( 2.8502e-01, 0.0000e+00, 4.6293e-01, 1.8581e+00),
( 6.2687e-01, 4.6293e-01, -1.1921e-07, 1.1171e+00),
( 1.7732e+00, 1.8581e+00, 1.1171e+00, -1.1921e-07)))
Probabilidad de muestreo
Ahora podemos calcular la matriz que representa la probabilidad de seleccionar cada característica dadas sus distancias por pares a todas las demás características. Esta es simplemente la probabilidad de elegir i puntos basados en las distancias entre i y j o k puntos.
Podemos calcular esto a través del siguiente código:
pairwise_distance_matrix = torch.exp(
-(distance_matrix / temperature)
) - torch.eye(features.shape(0)).to(model.device)
El código primero calcula el exponencial del negativo de la matriz de distancia dividido por el factor de temperatura, escalando los valores a valores positivos. El factor de temperatura dicta cómo controlar la importancia dada a las distancias entre pares de puntos; por ejemplo, a bajas temperaturas, la pérdida está dominada por distancias pequeñas, mientras que las distancias reales entre representaciones muy separadas se vuelven menos relevantes.
Antes de la resta de torch.eye(features.shape(0))
(también conocida como matriz diagonal), el tensor era el siguiente,
tensor(((1.0000, 0.7520, 0.5343, 0.1698),
(0.7520, 1.0000, 0.6294, 0.1560),
(0.5343, 0.6294, 1.0000, 0.3272),
(0.1698, 0.1560, 0.3272, 1.0000)))
Restamos una matriz diagonal de la matriz de distancias para eliminar todos los términos de autosemejanza (es decir, la distancia o similitud de cada punto consigo mismo).
A continuación, podemos calcular la probabilidad de muestreo para cada par de puntos de datos mediante el siguiente código:
pick_probability = pairwise_distance_matrix / (
torch.sum(pairwise_distance_matrix, 1).view(-1, 1)
+ stability_epsilon
)
Probabilidad de muestreo enmascarada
Hasta ahora, la probabilidad de muestreo que hemos calculado no contiene ninguna información de etiqueta. Integramos la información de la etiqueta en la probabilidad de muestreo enmascarándola con las etiquetas del conjunto de datos.
Primero, tenemos que derivar una matriz por pares a partir de los vectores de etiquetas:
masking_matrix = torch.squeeze(
torch.eq(labels, labels.unsqueeze(1)).float()
)
Aplicamos la matriz de enmascaramiento para usar la información de la etiqueta para aislar las probabilidades de puntos que pertenecen a la misma clase:
masked_pick_probability = pick_probability * masking_matrix
A continuación, calculamos la probabilidad suma para muestrear una característica particular calculando la suma de la probabilidad de muestreo enmascarada por fila,
summed_masked_pick_probability = torch.sum(masked_pick_probability, dim=1)
Finalmente, podemos calcular el logaritmo de la suma de las probabilidades de muestreo de características por conveniencia computacional con una variable de estabilidad computacional adicional, y obtener el promedio para que actúe como la pérdida del vecino más cercano para la red.
snnl = torch.mean(
-torch.log(summed_masked_pick_probability + stability_epsilon
)
Ahora podemos unir estos componentes en una función de paso directo para calcular la pérdida suave del vecino más cercano en todas las capas de una red neuronal profunda.
def forward(
self,
model: torch.nn.Module,
features: torch.Tensor,
labels: torch.Tensor,
outputs: torch.Tensor,
epoch: int,
) -> Tuple:
if self.use_annealing:
self.temperature = 1.0 / ((1.0 + epoch) ** 0.55)primary_loss = self.primary_criterion(
outputs, features if self.unsupervised else labels
)
activations = self.compute_activations(model=model, features=features)
layers_snnl = ()
for key, value in activations.items():
value = value(:, : self.code_units)
distance_matrix = self.pairwise_cosine_distance(features=value)
pairwise_distance_matrix = self.normalize_distance_matrix(
features=value, distance_matrix=distance_matrix
)
pick_probability = self.compute_sampling_probability(
pairwise_distance_matrix
)
summed_masked_pick_probability = self.mask_sampling_probability(
labels, pick_probability
)
snnl = torch.mean(
-torch.log(self.stability_epsilon + summed_masked_pick_probability)
)
layers_snnl.append(snnl)
snn_loss = torch.stack(layers_snnl).sum()
train_loss = torch.add(primary_loss, torch.mul(self.factor, snn_loss))
return train_loss, primary_loss, snn_loss
Visualizando representaciones desenredadas
Entrenamos un codificador automático con la pérdida suave del vecino más cercano y visualizamos sus representaciones desenredadas aprendidas. El codificador automático tenía unidades (x-500–500–2000-d-2000–500–500-x) y se entrenó en un pequeño subconjunto etiquetado de los conjuntos de datos MNIST, Fashion-MNIST y EMNIST-Balanced. Esto es para simular la escasez de ejemplos etiquetados, ya que se supone que los codificadores automáticos son modelos no supervisados.
Solo visualizamos 10 grupos elegidos arbitrariamente para una visualización más fácil y limpia del conjunto de datos equilibrado de EMNIST. Podemos ver en la figura anterior que la representación del código latente se volvió más amigable con la agrupación al tener un conjunto de grupos bien definidos como lo indica la dispersión de los grupos y asignaciones correctas de los grupos como lo indican los colores de los grupos.
Comentarios finales
En este artículo, analizamos la función de pérdida suave del vecino más cercano y cómo podríamos implementarla en PyTorch.
La pérdida suave del vecino más cercano fue introducida por primera vez por Salakhutdinov y Hinton (2007) donde se usó para calcular la pérdida en la representación del código latente (cuello de botella) de un codificador automático, y luego dicha representación se usó para la tarea de clasificación kNN posterior.
Frost, Papernot y Hinton (2019) luego expandió la pérdida suave del vecino más cercano introduciendo un factor de temperatura y calculando la pérdida en todas las capas de una red neuronal.
Finalmente, empleamos un factor de temperatura de recocido para la pérdida suave del vecino más cercano para mejorar aún más las representaciones desenredadas aprendidas de una red y también acelerar el proceso de desenredado (agarap y azúcar,).
La implementación completa del código está disponible en GitLab.
Referencias
- Agarap, Abien Fred y Arnulfo P. Azcárraga. “Mejorar el rendimiento de la agrupación de k-significa con representaciones internas desenredadas”. Conferencia conjunta internacional sobre redes neuronales 2020 (IJCNN). IEEE, 2020.
- Chapelle, Olivier, Bernhard Scholkopf y Alexander Zien. “Aprendizaje semisupervisado (chapelle, o. et al., eds.; 2006) (reseñas de libros)”. Transacciones IEEE en redes neuronales 20.3 (2009): 542–542.
- Frosst, Nicholas, Nicolas Papernot y Geoffrey Hinton. “Analizar y mejorar las representaciones con la pérdida suave del vecino más cercano”. Conferencia internacional sobre aprendizaje automático. PMLR, 2019.
- Goldberger, Jacob y cols. “Análisis de componentes del barrio”. Avances en los sistemas de procesamiento de información neuronal.. 2005.
- Él, Kaiming, et al. “Aprendizaje residual profundo para el reconocimiento de imágenes”. Actas de la conferencia IEEE sobre visión por computadora y reconocimiento de patrones. 2016.
- Hinton, G., et al. “Análisis de componentes del barrio”. Proc. PNI. 2004.
- Krizhevsky, Alex, Ilya Sutskever y Geoffrey E. Hinton. “Clasificación de imágenes con redes neuronales convolucionales profundas”. Avances en los sistemas de procesamiento de información neuronal. 25 (2012).
- Roweis, Sam T. y Lawrence K. Saul. “Reducción de dimensionalidad no lineal mediante incrustación lineal local”. ciencia 290,5500 (2000): 2323–2326.
- Salakhutdinov, Ruslan y Geoff Hinton. “Aprender una integración no lineal preservando la estructura del vecindario de clases”. Inteligencia artificial y estadística. 2007.
- Simonyan, Karen y Andrew Zisserman. “Redes convolucionales muy profundas para el reconocimiento de imágenes a gran escala”. preimpresión de arXiv arXiv:1409.1556 (2014).
- Van der Maaten, Laurens y Geoffrey Hinton. “Visualización de datos utilizando t-SNE”. Revista de investigación sobre aprendizaje automático 9.11 (2008).