Extracción de características usando LSH

Locality Sensitive Hashing (LSH) se utiliza a menudo para las operaciones de aproximación del vecino más cercano (ANN) (búsqueda de vectores). Las propiedades de LSH también se pueden explotar en modelos de redes neuronales que toman vectores como entrada (por ejemplo, varias señales de contenido, como incrustaciones de audio, video y texto).

A menudo, las variedades de entrada en modelos específicos de dominio son complejas (no II-D). Esta complejidad hace que sea muy difícil separar estas variedades utilizando operaciones computacionalmente intensivas de perceptrones multicapa. El esquema clásico para aprender mapeos complejos es memorizar resultados, en lugar de funciones de aprendizaje. ¿Cómo memorizar gráficos vectoriales? El enfoque más directo es la incorporación de vectores. Pero necesitamos objetos discretos para calcular incrustaciones, y los vectores no son discretos. Entonces, ¿cómo aplicar el algoritmo de incrustación de vectores a la entrada de vectores? Hash el vector, los puntos cercanos deben permanecer "cerca" después de hash. Esto es lo que hace LSH, por lo que la incrustación en la parte superior de mi operación LSH se puede usar como un extractor de características superficiales.

"Locality Sensitive Hashing" (LSH para abreviar) es una técnica de búsqueda aproximada para resolver tales problemas. Su idea principal es mapear puntos de datos similares en el mismo cubo "hash", de modo que se pueda realizar una búsqueda en un cubo específico en lugar de hacer una búsqueda lineal en todo el conjunto de datos. Si bien este enfoque no garantiza encontrar los vecinos más cercanos exactos, proporciona un método de búsqueda aproximado eficiente en datos de alta dimensión.

Los conceptos básicos de LSH son los siguientes:

  1. Función Sensible a la Localidad : Esta es una función que puede mapear puntos de datos similares en el mismo depósito hash, pero no es tan estricta, por lo que incluso si algunos puntos de datos se asignan al mismo depósito, no tienen que ser realmente parecido, tampoco. El diseño de la función de sensibilidad local depende del tipo de datos que se procesan y la medida de similitud.
  2. Cubo de hash : los puntos de datos se asignan a diferentes cubos de hash a través de una función de sensibilidad local. Se pueden asignar puntos de datos similares al mismo depósito, proporcionando un punto de partida para la búsqueda.
  3. Tabla hash : los cubos hash constituyen una tabla hash, y al buscar en la tabla hash, los puntos de datos con similitudes se pueden ubicar rápidamente.

El rendimiento de LSH depende del diseño de la función de sensibilidad local y la construcción de cubos de hash. Esto implica mapear puntos de datos en cubos distintos manteniendo la similitud y organizando y recuperando datos en una tabla hash. LSH generalmente se usa para resolver el problema de búsqueda aproximada del vecino más cercano (Búsqueda aproximada del vecino más cercano, ANN), donde el objetivo es encontrar un punto de datos con una gran similitud con un punto de consulta dado.

La elección del algoritmo LSH y la forma de convertir cubos LSH en incrustaciones es muy importante. Así que aquí hay solo un algoritmo consciente de la dirección (ignorando el tamaño del vector), que se basa en este algoritmo LSH simple:

 import torch
 import torch.nn as nn
 import torch.nn.functional as F
 
 
 class CosineVectorEmbedding(nn.Module):
     """
     LSH based vector indexer for highly non-linear ops
     """
 
     def __init__(self, inp_dim: int, emb_dim: int, n_proj: int = 16, num_bins: int = 20):
         super().__init__()
         self.register_buffer(
             'projection_mat',
             F.normalize(torch.randn((inp_dim, n_proj)), p=2.0, dim=0),
             persistent=True,
         )
         resolution = 2.0 / num_bins
         self.register_buffer(
             'grid',
             torch.linspace(-1, 1, num_bins + 1)[:-1] + 0.5 * resolution,
             persistent=True,
         )
         self.register_buffer(
             'pos_offset',
             ((num_bins + 1) * torch.arange(0, n_proj, dtype=torch.long)).long().reshape(-1, 1, 1),
             persistent=True
         )
         self.emb = nn.EmbeddingBag((num_bins + 1) * n_proj, emb_dim)
         self.emb_dim = emb_dim
         self.n_proj = n_proj
 
     def forward(self, x):
         bs, seq_len, emb_dim = x.size()
         z = F.normalize(x, p=2.0, dim=-1) @ self.projection_mat
         z = torch.bucketize(z, self.grid).transpose(0, -1)
         z = (z + self.pos_offset).transpose(0, -1).contiguous()
         return self.emb(z.view(-1, self.n_proj)).reshape(bs, seq_len, self.emb_dim)

Para ilustrar su efectividad, lo aplicamos al entrenamiento del RecSys LLM alimentado con una incrustación de contenido de entrada de 32 dimensiones. Utilice una incrustación de LSH en cascada independiente de baja a alta resolución (inp_dim=32, emb_dim=512, n_proj=32, num_bins=(1, 2, 4, 8, 12, 16, 20)) y genere la suma. Esto se compara con el uso de una proyección simple (usando nn.Linear(32, 512)).

Se puede ver que nuestro CosineVectorEmbedding es un mejor extractor de características que una simple transformación lineal (por supuesto, más parámetros y mayor eficiencia computacional).

https://evitar.overfit.cn/post/2bab364a679f4b6f8d9a1c0bd3096b9b

Por Dinesh Ramasamy

Supongo que te gusta

Origin blog.csdn.net/m0_46510245/article/details/132256962
Recomendado
Clasificación