redes neuronales y Agrupación Los algoritmos parecen mundos separados. Las redes neuronales se usan típicamente en el aprendizaje supervisado, donde el objetivo es etiquetar nuevos datos basados en patrones aprendidos de un conjunto de datos etiquetado. La agrupación, por el contrario, suele ser una tarea no supervisada: tratamos de descubrir las relaciones en los datos sin acceso a etiquetas de verdad terrestre.
Como resultado Aprendizaje profundo Puede ser increíblemente útil para problemas de agrupación. Aquí está la idea clave: supongamos que entrenamos una red neuronal utilizando una función de pérdida que refleje algo que nos importa, digamos, qué tan bien podemos clasificar o separar ejemplos. Si la red logra una baja pérdida, podemos inferir que el representaciones Aprende (especialmente en la capa secundaria de la segunda a la) estructura significativa en los datos. En otras palabras, estas representaciones intermedias codifican lo que la red ha aprendido sobre la tarea.
Entonces, ¿qué sucede si ejecutamos un algoritmo de agrupación (como Kmeans) en esas representaciones? Idealmente, terminamos con grupos que reflejan la misma estructura subyacente que la red fue entrenada para capturar.
¡Ahh, eso es mucho! Aquí hay una foto:
Como se ve en la imagen, cuando ejecutamos nuestras entradas hasta la segunda capa de la segunda, obtenemos un vector con valores de Kₘ, que presumiblemente es mucho menor que la cantidad de entradas con las que comenzamos si hicimos todo bien. Porque la capa de salida mira únicamente a este vector al hacer prediccionessi nuestras predicciones son buenas, podemos concluir que este vector encapsula cierta información importante sobre nuestros datos. La agrupación en este espacio es más significativa que la agrupación de datos sin procesar, ya que hemos filtrado para las características que realmente importan.
Esta es la idea fundamental detrás Titube de profundidad– a Red neuronal enfoque para la agrupación. En lugar de agrupar los datos sin procesar directamente, DeepType primero aprende una representación relevante para la tarea a través del entrenamiento supervisado y luego realiza la agrupación en ese espacio aprendido.
Sin embargo, esto plantea una pregunta: si ya tenemos etiquetas de verdad en tierra, ¿por qué necesitaríamos ejecutar la agrupación? Después de todo, si solo nos agrupamos usando nuestras etiquetas, ¿no crearía eso una agrupación perfecta? Luego, para nuevos puntos de datos, podríamos simplemente ejecutar nuestra red neuronal, predecir la etiqueta y agrupar el punto adecuadamente.
Resulta que, en algunos contextos, Nos importa más las relaciones entre nuestros puntos de datos que las propias etiquetas. En el Documento que introdujo DeepTypepor ejemplo, los autores utilizaron la idea descrita para encontrar diferentes grupos de pacientes con cáncer de mama basados en datos genéticos, lo cual es muy útil en un contexto biológico. Luego encontraron que estos grupos se correlacionaron muy bien con las tasas de supervivencia, lo que tiene sentido dado que las representaciones en las que se agruparon estaban arraigadas con conocimiento biológico.
Refinar la idea: función de pérdida de DeepType
En este punto, entendemos la idea central: capacitar a una red neuronal para aprender una representación relevante para tareas, luego agrupar en ese espacio. Sin embargo, podemos hacer algunas modificaciones ligeras para mejorar este proceso.
Para empezar, nos gustaría los grupos que producimos para ser compactos si es posible. En otras palabras, preferiríamos tener la situación en la imagen a la izquierda que a la derecha:
Para hacer esto, queremos impulsar las representaciones de los puntos de datos en los mismos grupos para que estén lo más cerca posible. Para hacer esto, agregamos un término a nuestra función de pérdida que penaliza la distancia entre la representación de nuestra entrada y el centro del clúster al que se ha asignado. Por lo tanto, nuestra función de pérdida se convierte en
Dónde d es una función de distancia entre los vectores, es decir, el cuadrado de la norma de la diferencia entre los vectores (como se usa en el papel original).
Pero espera, ¿cómo obtenemos los centros de clúster si aún no hemos entrenado la red? Para evitar eso, DeepType realiza el siguiente procedimiento:
- Entrenar un modelo solo en la pérdida principal
- Cree grupos en el espacio de representación (usando EG KMeans o su algoritmo favorito)
- Entrene el modelo utilizando la pérdida modificada
- Regrese al paso 2 y repita hasta que convergamos
Finalmente, este procedimiento produce grupos compactos que con suerte corresponden a nuestra pérdida de interés.
Encontrar entradas importantes
En contextos donde DeepType es útil, además de preocuparse por los grupos, también nos importa qué aportes son los más informativos/importantes. El documento que introdujo DeepType, por ejemplo, estaba interesado en determinar qué genes eran los más importantes para determinar el subtipo de cáncer de alguien; dicha información es ciertamente útil para un biólogo. Muchos otros contextos también encontrarían dicha información interesante; de hecho, es difícil soñar con uno que no lo haría.
En un contexto de aprendizaje profundo, podemos considerar que una entrada es importante si la magnitud de los pesos asignados por los nodos en la primera capa es alta. Por el contrario, si la mayoría de nuestros nodos tienen un peso cercano a 0 para la entrada, no contribuirá mucho a nuestra predicción final y, por lo tanto, probablemente no sea tan importante.
Por lo tanto, presentamos un término de pérdida final: un pérdida de dispersión –Eso alentará a nuestra red neuronal a llevar la mayor cantidad posible de pesos de entrada a 0. Con eso, nuestra pérdida de profundidad profunda modificada final se convierte en
Donde el término beta es el término de distancia que teníamos antes, y el término alfa penaliza efectivamente una alta “magnitud” de la matriz de peso de la primera capa.
También modificamos el procedimiento de cuatro pasos de la sección anterior ligeramente. En lugar de solo entrenar en el MSE en el primer paso, entrenaremos tanto en el MSE como en la pérdida de escasez en el paso previo. Según los autores, nuestra estructura final de DeepType se ve así:
Jugando con DeepType
Como parte de mi investigación, he publicado un Implementación de código abierto de DeepType aquí. Además, puede descargarlo de Pip haciendo pip install torch-deeptype .
El paquete DeepType utiliza una infraestructura bastante simple para probar todo. Como ejemplo, crearemos un conjunto de datos sintético con cuatro grupos y 20 entradas, solo 5 de los cuales realmente contribuyen a la salida:
import numpy as np
import torch
from torch.utils.data import TensorDataset, DataLoader
# 1) Configuration
n_samples = 1000
n_features = 20
n_informative = 5 # number of "important" features
n_clusters = 4 # number of ground-truth clusters
noise_features = n_features - n_informative
# 2) Create distinct cluster centers in the informative subspace
# (spread out so clusters are well separated)
informative_centers = np.random.randn(n_clusters, n_informative) * 5
# 3) Assign each sample to a cluster, then sample around that center
X_informative = np.zeros((n_samples, n_informative))
y_clusters = np.random.randint(0, n_clusters, size=n_samples)
for i, c in enumerate(y_clusters):
center = informative_centers[c]
X_informative[i] = center + np.random.randn(n_informative)
# 4) Generate pure noise for the remaining features
X_noise = np.random.randn(n_samples, noise_features)
# 5) Concatenate informative + noise features
X = np.hstack([X_informative, X_noise]) # shape (1000, 20)
y = y_clusters # shape (1000,)
# 6) Convert to torch tensors and build DataLoader
X_tensor = torch.from_numpy(X).float()
y_tensor = torch.from_numpy(y).long()
dataset = TensorDataset(X_tensor, y_tensor)
train_loader = DataLoader(dataset, batch_size=64, shuffle=True)
Así es como se ven nuestros datos cuando trazamos un PCA:
Entonces definiremos unDeeptypeModel– Puede ser cualquier infraestructura siempre que implementa el forward , get_input_layer_weights y get_hidden_representations Funciones:
import torch
import torch.nn as nn
from torch_deeptype import DeeptypeModel
class MyNet(DeeptypeModel):
def __init__(self, input_dim: int, hidden_dim: int, output_dim: int):
super().__init__()
self.input_layer = nn.Linear(input_dim, hidden_dim)
self.h1 = nn.Linear(hidden_dim, hidden_dim)
self.cluster_layer = nn.Linear(hidden_dim, hidden_dim // 2)
self.output_layer = nn.Linear(hidden_dim // 2, output_dim)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# Notice how forward() gets the hidden representations
hidden = self.get_hidden_representations(x)
return self.output_layer(hidden)
def get_input_layer_weights(self) -> torch.Tensor:
return self.input_layer.weight
def get_hidden_representations(self, x: torch.Tensor) -> torch.Tensor:
x = torch.relu(self.input_layer(x))
x = torch.relu(self.h1(x))
x = torch.relu(self.cluster_layer(x))
return x
Entonces, creamos un DeeptypeTrainer y entrenar:
from torch_deeptype import DeeptypeTrainer
trainer = DeeptypeTrainer(
model = MyNet(input_dim=20, hidden_dim=64, output_dim=5),
train_loader = train_loader,
primary_loss_fn = nn.CrossEntropyLoss(),
num_clusters = 4, # K in KMeans
sparsity_weight = 0.01, # α for L₂ sparsity on input weights
cluster_weight = 0.5, # β for cluster‐rep loss
verbose = True # print per-epoch loss summaries
)
trainer.train(
main_epochs = 15, # epochs for joint phase
main_lr = 1e-4, # LR for joint phase
pretrain_epochs = 10, # epochs for pretrain phase
pretrain_lr = 1e-3, # LR for pretrain (defaults to main_lr if None)
train_steps_per_batch = 8, # inner updates per batch in joint phase
)
Después del entrenamiento, podemos extraer fácilmente las entradas importantes
sorted_idx = trainer.model.get_sorted_input_indices()
print("Top 5 features by importance:", sorted_idx[:5].tolist())
print(trainer.model.get_input_importance())
>> Top 5 features by importance: [3, 1, 4, 2, 0]
>> tensor([0.7594, 0.8327, 0.8003, 0.9258, 0.8141, 0.0107, 0.0199, 0.0329, 0.0043,
0.0025, 0.0448, 0.0054, 0.0119, 0.0021, 0.0190, 0.0055, 0.0063, 0.0073,
0.0059, 0.0189], grad_fn=<LinalgVectorNormBackward0>)
Lo cual es increíble, ¡recuperamos las 5 entradas importantes como se esperaba!
También podemos extraer fácilmente los clústeres usando la capa de representación y trazarlos:
centroids, labels = trainer.get_clusters(dataset)
plt.figure(figsize=(8, 6))
plt.scatter(
components[:, 0],
components[:, 1],
c=labels,
cmap='tab10',
s=20,
alpha=0.7
)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.title('PCA of Synthetic Dataset')
plt.colorbar(label='True Cluster')
plt.tight_layout()
plt.show()
¡Y BOOM, eso es todo!
Conclusión
Aunque DeepType no será la herramienta adecuada para cada problema, ofrece una forma poderosa de integrar el conocimiento del dominio en el proceso de agrupación. Entonces, si te encuentras con una función de pérdida significativa y un deseo de descubrir la estructura en tus datos, ¡das un tiro profundo!
Por favor contactar [email protected] para cualquier consulta. Todas las imágenes del autor a menos que se indique lo contrario.
- Los biólogos han determinado un conjunto de subtipos de cáncer para la categoría más amplia de cáncer de mama. Aunque no soy un experto, es seguro asumir que estos subtipos fueron identificados por biólogos por una razón. Los autores capacitaron a su modelo para predecir el subtipo de un paciente, que proporcionó el contexto biológico necesario para producir nuevos e interesantes grupos. Sin embargo, dado el objetivo, no estoy seguro de por qué los autores eligieron predecir en subtipos en lugar de los resultados del paciente directamente, sin embargo, de hecho, apuesto a que los resultados de dicho experimento serían interesantes.
- La norma presentada se define como
Transponemos W ya que queremos penalizar las columnas de la matriz de peso en lugar de las filas. Esto es importante porque en una capa de red neuronal totalmente conectada, Cada columna de la matriz de peso corresponde a una función de entrada. Al aplicar la norma ℓ2,1 a la matriz transpuesta, alentamos a las características de entrada completas para que se concentren, promoviendo la escasez a nivel de características
Fuente de la imagen de portada: aquí