es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo implementar de manera eficiente una capa lineal no completamente conectada en PyTorch?

Realicé un diagrama de ejemplo de una versión reducida de lo que estoy tratando de implementar:

network diagram

Así que los dos nodos de entrada superiores solo están completamente conectados a los tres nodos de salida superiores, y el mismo diseño se aplica a los dos nodos inferiores. Hasta ahora se me ocurrieron dos formas de implementar esto en PyTorch, ninguno de los cuales es óptimo.

La primera sería crear un nn.ModuleList de varias capas Lineales más pequeñas, y durante el pase hacia adelante, iterar la entrada a través de ellas. Para el ejemplo del diagrama, se vería algo así:

class Module(nn.Module):
  def __init__(self):
    self.layers = nn.ModuleList([nn.Linear(2, 3) for i in range(2)])

  def forward(self, input):
    output = torch.zeros(2, 3)
    for i in range(2):
      output[i, :] = self.layers[i](input.view(2, 2)[i, :])
    return output.flatten()

Por lo tanto, esto logra la red del diagrama, el principal problema es que es muy lento. Supongo que esto se debe a que PyTorch tiene que procesar el bucle for secuencialmente y no puede procesar el tensor de entrada en paralelo.

Para “vectorizar” el módulo de manera que PyTorch pueda ejecutarlo más rápido, tengo esta implementación:

class Module(nn.Module):
  def __init__(self):
    self.layer = nn.Linear(4, 6)
    self.mask = # crear una máscara de unos y ceros para "bloquear" ciertas conexiones de las capas

  def forward(self, input):
    prune.custom_from_mask(self.layer, name='weight', mask=self.mask)
    return self.layer(input)

Esto también logra la red del diagrama, utilizando la poda de pesos para asegurarse de que ciertos pesos en la capa completamente conectada siempre sean cero (por ejemplo, el peso que conecta el nodo de entrada superior con el nodo de salida inferior siempre será cero, por lo que está efectivamente “desconectado”). Este módulo es mucho más rápido que el anterior, ya que no hay un bucle for. El problema ahora es que este módulo ocupa significativamente más memoria. Esto probablemente se debe al hecho de que, aunque la mayoría de los pesos de la capa serán cero, PyTorch aún trata la red como si estuvieran allí. Esta implementación mantiene alrededor muchos más pesos de los necesarios.

¿Alguien ha encontrado este problema antes y ha encontrado una solución eficiente?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Implementación eficiente de una red neuronal completamente conectada dispersa utilizando PyTorch

    Me he encontrado con el problema de implementar una red neuronal completamente conectada dispersa en PyTorch, y después de algunas experimentaciones, he encontrado una solución más eficiente que es más rápida y utiliza menos memoria.

    La solución consiste en utilizar la capa lineal enmascarada integrada de PyTorch, que nos permite aplicar una máscara a los pesos para bloquear eficazmente ciertas conexiones. Para crear la máscara, podemos empezar con una capa totalmente conectada densa y establecer manualmente ciertos pesos a cero en función del patrón de dispersión deseado.

    Aquí hay un ejemplo de implementación de una red neuronal completamente conectada dispersa utilizando la capa lineal enmascarada:

    import torch
    import torch.nn as nn
    
    class SparseModule(nn.Module):
        def __init__(self):
            super(SparseModule, self).__init__()
            self.layer = nn.Linear(4, 6)
            self.mask = torch.tensor([ [1, 1, 0, 0, 0, 0],
                                       [1, 1, 0, 0, 0, 0],
                                       [0, 0, 1, 1, 0, 0],
                                       [0, 0, 1, 1, 0, 0] ]).float()
            self.masked_layer = nn.utils.weight_norm(nn.utils.prune.CustomFromMask(
                self.layer, name='weight', mask=self.mask))
    
        def forward(self, x):
            return self.masked_layer(x)
    
    

    En esta implementación, la máscara es un tensor binario que especifica qué pesos mantener y cuáles establecer a cero. Al utilizar el método de poda CustomFromMask con el envoltorio weight_norm, podemos crear una capa lineal enmascarada que solo tiene los pesos diferentes de cero. Esto ahorra memoria al almacenar solo los pesos diferentes de cero y acelera el cálculo al no tener que procesar las conexiones con peso cero.

    Esta implementación combina las ventajas de los enfoques anteriores: es rápida y eficiente en memoria. Sin embargo, la creación de la máscara puede llevar tiempo y puede requerir cierta prueba y error para encontrar el patrón de dispersión óptimo para una tarea determinada.

    En general, esta implementación representa una solución eficiente para implementar redes neuronales completamente conectadas dispersas utilizando PyTorch.

Comments are closed.