notícias

Como funcionam os autoencoders esparsos, aqui está uma explicação intuitiva

2024-08-05

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina



Relatório do coração da máquina

Editor: Panda

Resumindo: matriz → ativação ReLU → matriz

Autoencoders esparsos (SAEs) são uma ferramenta cada vez mais comum para interpretar modelos de aprendizado de máquina (embora os SAEs existam desde 1997).

Os modelos de aprendizagem automática e os LLMs estão a tornar-se cada vez mais poderosos e úteis, mas ainda são caixas negras e não compreendemos como realizam as suas tarefas. Compreender como eles funcionam deve ser muito útil.

SAE nos ajuda a dividir os cálculos de um modelo em componentes compreensíveis. Recentemente, o pesquisador de interpretabilidade do LLM, Adam Karvonen, publicou uma postagem no blog para explicar intuitivamente como funciona o SAE.

O problema da interpretabilidade

Os componentes mais naturais das redes neurais são os neurônios individuais. Infelizmente, um único neurônio não corresponde convenientemente a um único conceito, como uma citação acadêmica, uma conversa em inglês, uma solicitação HTTP e um texto em coreano. Nas redes neurais, os conceitos são representados por meio de combinações de neurônios, o que é chamado de superposição.

A razão para isto é que muitas variáveis ​​no mundo são naturalmente escassas.

Por exemplo, o local de nascimento de uma celebridade pode aparecer em menos de um entre um bilhão de tokens de treinamento, mas os LLMs modernos ainda podem aprender esse fato e uma riqueza de outros conhecimentos sobre o mundo. Existem mais fatos e conceitos individuais nos dados de treinamento do que neurônios no modelo, provavelmente por isso que ocorre a superposição.

Recentemente, a tecnologia de autoencoder esparso (SAE) tem sido cada vez mais usada para decompor redes neurais em componentes compreensíveis. O design do SAE é inspirado na hipótese de codificação esparsa da neurociência. Hoje, SAE se tornou uma das ferramentas mais promissoras para interpretação de redes neurais artificiais. SAE é semelhante a um autoencoder padrão.

Um autoencoder convencional é uma rede neural usada para compactar e reconstruir dados de entrada.

Por exemplo, se a entrada for um vetor de 100 dimensões (uma lista contendo 100 valores); o autoencoder primeiro passa a entrada por uma camada do codificador para compactá-la em um vetor de 50 dimensões e, em seguida, compacta essa representação codificada. o decodificador para obter um vetor de saída de 100 dimensões. O processo de reconstrução geralmente não é perfeito, pois o processo de compressão dificulta muito a tarefa de reconstrução.



Diagrama esquemático de um autoencoder padrão com um vetor de entrada 1x4, um vetor de estado intermediário 1x2 e um vetor de saída 1x4. A cor da célula representa o valor de ativação. A saída é uma reconstrução imperfeita da entrada.

Explicando autoencoders esparsos

Como funcionam os codificadores automáticos esparsos

Um autoencoder esparso converte um vetor de entrada em um vetor intermediário que pode ter dimensões superiores, iguais ou inferiores à entrada. Quando usados ​​no LLM, os vetores intermediários geralmente possuem dimensões maiores que a entrada. Neste caso, sem restrições adicionais, a tarefa é simples e o SAE pode usar a matriz identidade para reconstruir perfeitamente a entrada sem surpresas. Mas adicionaremos restrições, uma das quais é adicionar uma penalidade de dispersão à perda de treinamento, o que fará com que o SAE crie vetores intermediários esparsos.

Por exemplo, podemos expandir uma entrada de 100 dimensões em um vetor de representação codificado de 200 dimensões e podemos treinar o SAE para ter apenas cerca de 20 elementos diferentes de zero na representação codificada.



Diagrama esquemático do autoencoder esparso. Observe que as ativações intermediárias são esparsas, com apenas 2 valores diferentes de zero.

Usamos SAE para ativações intermediárias em redes neurais, que podem conter muitas camadas. Durante a passagem direta, há ativações intermediárias dentro de cada camada e entre cada camada.

Por exemplo, GPT-3 possui 96 camadas. Durante a passagem direta, cada token na entrada possui um vetor de 12.288 dimensões (uma lista de 12.288 valores). Esse vetor acumula todas as informações utilizadas pelo modelo para prever o próximo token em cada camada de processamento, mas é opaco, dificultando a compreensão de quais informações ele contém.

Podemos usar SAE para entender essa ativação intermediária. SAE é basicamente "matriz → ativação ReLU → matriz".

Por exemplo, se o fator de expansão do GPT-3 SAE for 4 e suas ativações de entrada tiverem 12.288 dimensões, então sua representação codificada por SAE terá 49.512 dimensões (12.288 x 4). A primeira matriz é a matriz codificadora de forma (12.288, 49.512) e a segunda matriz é a matriz decodificadora de forma (49.512, 12.288). Multiplicando as ativações GPT pelo codificador e usando ReLU, uma representação esparsa codificada SAE de 49.512 dimensões pode ser obtida porque a função de perda SAE promove a dispersão.

Em geral, nosso objetivo é ter menos de 100 valores diferentes de zero na representação SAE. Ao multiplicar a representação SAE pelo decodificador, obtém-se uma ativação do modelo reconstruído de 12.288 dimensões. Esta reconstrução não corresponde perfeitamente às ativações originais do GPT porque as restrições de dispersão dificultariam a obtenção de uma combinação perfeita.

De modo geral, um SAE é usado apenas para uma posição no modelo. Por exemplo, podemos treinar um SAE em ativações intermediárias entre as camadas 26 e 27. Para analisar as informações contidas nas saídas de todas as 96 camadas do GPT-3, 96 SAEs separados podem ser treinados – um para a saída de cada camada. Se também quiséssemos analisar as diversas ativações intermediárias dentro de cada camada, seriam necessárias centenas de SAEs. Para obter dados de treinamento para esses SAEs, uma grande quantidade de textos diferentes precisa ser inserida neste modelo GPT e, em seguida, as ativações intermediárias para cada posição selecionada são coletadas.

Uma implementação de referência do PyTorch do SAE é fornecida abaixo. As variáveis ​​são anotadas com formas. Essa ideia vem de Noam Shazeer, veja: https://medium.com/@NoamShazeer/shape-suffixes-good-coding-style-f836e72e24fd. Observe que, para maximizar o desempenho, diferentes implementações SAE geralmente têm diferentes termos de polarização, esquemas de normalização ou esquemas de inicialização. Uma das adições mais comuns é algum tipo de restrição na norma do vetor decodificador. Para mais detalhes, visite a implementação abaixo:

  • OpenAI:https://github.com/openai/sparse_autoencoder/blob/main/sparse_autoencoder/model.py#L16
  • SAELens: https://github.com/jbloomAus/SAELens/blob/main/sae_lens/sae.py#L97
  • aprendizagem_dicionário:https://github.com/saprmarks/dictionary_learning/blob/main/dictionary.py#L30

importar tocha

importar torch.nn como nn

# D = d_model, F = tamanho_dicionário

# por exemplo se d_model = 12288 e dictionary_size = 49152

# então model_activations_D.shape = (12288,) e encoder_DF.weight.shape = (12288, 49152)

classe SparseAutoEncoder (nn.Module):

Um autocodificador de uma camada.

def __init__(self, ativação_dim: int, tamanho_do_dict: int):

super().__init__()

self.activation_dim = dim_ativação

self.dict_size = tamanho_do_dict

self.encoder_DF = nn.Linear (ativação_dim, dict_size, bias=True)

self.decoder_FD = nn.Linear (tamanho_do_dict, ativação_dim, viés=Verdadeiro)

def codificar (self, model_activations_D: tocha.Tensor) -> tocha.Tensor:

retornar nn.ReLU ()(self.encoder_DF (model_activations_D))

def decodificar (self, representação_codificada_F: tocha.Tensor) -> tocha.Tensor:

retornar self.decoder_FD (representação_codificada_F)

def forward_pass (self, model_activations_D: tocha.Tensor) -> tupla [torch.Tensor, tocha.Tensor]:

representação_codificada_F = self.encode (ativações_modelo_D)

reconstruído_modelo_ativações_D = self.decode (codificado_representação_F)

retornar reconstruído_modelo_ativações_D, representação_codificada_F

A função de perda de um autoencoder padrão é baseada na precisão do resultado da reconstrução de entrada. Para introduzir a dispersão, a maneira mais direta é adicionar um termo de penalidade de dispersão à função de perda do SAE. A maneira mais comum de calcular este termo de penalidade é pegar a perda L1 da representação codificada deste SAE (não os pesos SAE) e multiplicá-la por um coeficiente L1. Este coeficiente L1 é um hiperparâmetro chave no treinamento SAE porque determina o compromisso entre alcançar a dispersão e manter a precisão da reconstrução.

Observe que isso não é otimizado para interpretabilidade. Em vez disso, os recursos SAE interpretáveis ​​são um efeito colateral da otimização da dispersão e da reconstrução. Abaixo está uma função de perda de referência.

# B = tamanho do lote, D = d_model, F = dictionary_size

def calculate_loss (autoencoder: SparseAutoEncoder, model_activations_BD: torch.Tensor, l1_coeffient: float) -> torch.Tensor:

reconstruído_modelo_ativações_BD, representação_codificada_BF = autoencoder.forward_pass (modelo_ativações_BD)

reconstruction_error_BD = (reconstruído_modelo_ativações_BD - modelo_ativações_BD).pow (2)

reconstruction_error_B = einops.reduce (reconstruction_error_BD, 'BD -> B', 'soma')

l2_loss = erro_de_reconstrução_B.mean()

l1_loss = l1_coefficient * representação_codificada_BF.sum ()

perda = l2_perda + l1_perda

perda de retorno



Diagrama esquemático da passagem direta de um autoencoder esparso.

Esta é uma única passagem direta do autoencoder esparso. O primeiro é o vetor modelo de tamanho 1x4. Isso é então multiplicado por uma matriz codificadora 4x8 para obter um vetor codificado 1x8 e ReLU é aplicado para transformar valores negativos em zero. Este vetor codificado é esparso. Em seguida, multiplique-o por uma matriz decodificadora 8x4 para obter uma ativação do modelo 1x4 reconstruída imperfeitamente.

Demonstração hipotética do recurso SAE

Idealmente, cada valor numérico significativo na representação SAE corresponde a algum componente compreensível.

Aqui assumimos um caso para ilustração. Suponha que um vetor de 12.288 dimensões [1,5, 0,2, -1,2, ...] represente "Golden Retriever" na visão do GPT-3. SAE é uma matriz de forma (49.512, 12.288), mas também podemos pensar nela como um conjunto de 49.512 vetores, cada um dos quais tem forma (1, 12.288). Se o vetor 317 do decodificador SAE aprender o mesmo conceito de "Golden Retriever" do GPT-3, então o vetor do decodificador será aproximadamente igual a [1,5, 0,2, -1,2, ...].

Sempre que o elemento 317 da ativação SAE for diferente de zero, então o vetor correspondente ao "Golden Retriever" (e baseado na magnitude do elemento 317) é adicionado à ativação reconstruída. Em termos de interpretabilidade mecânica, isso pode ser descrito sucintamente como “o vetor decodificador corresponde a uma representação linear das características no espaço de fluxo residual”.

Pode-se dizer também que o SAE com 49.512 dimensões de representação codificada possui 49.512 características. Os recursos consistem em vetores codificadores e decodificadores correspondentes. A função do vetor codificador é detectar os conceitos internos do modelo enquanto minimiza a interferência de outros conceitos, enquanto a função do vetor decodificador é representar a direção "real" do recurso. Os experimentos dos pesquisadores descobriram que os recursos do codificador e do decodificador de cada recurso são diferentes e a similaridade mediana do cosseno é de 0,5. Na imagem abaixo, as três caixas vermelhas correspondem a características individuais.



Diagrama esquemático do autoencoder esparso, em que as três caixas vermelhas correspondem ao recurso SAE 1 e a caixa verde corresponde ao recurso 4. Cada recurso possui um vetor codificador 1x4, ativações de recursos 1x1 e um vetor decodificador 1x4. As ativações reconstruídas foram construídas usando apenas vetores decodificadores dos recursos SAE 1 e 4. Se a caixa vermelha representa “cor vermelha” e a caixa verde representa “bola”, então o modelo pode representar “bola vermelha”.

Então, como sabemos o que o recurso hipotético 317 representa? Atualmente, a prática é procurar entradas que maximizem a ativação de recursos e dêem uma resposta intuitiva à sua interpretabilidade. As entradas que ativam cada recurso geralmente são interpretáveis.

Por exemplo, a Anthropic treinou SAE em Claude Sonnet e descobriu que textos e imagens relacionados à Ponte Golden Gate, neurociência e atrações turísticas populares ativavam diferentes recursos do SAE. Outras características serão ativadas por conceitos que não são óbvios. Por exemplo, uma característica de um SAE treinado em Pítia será ativada pelo conceito de “o token final de uma cláusula relativa ou frase preposicional usada para modificar o sujeito da frase. "

Como o vetor decodificador SAE tem o mesmo formato das ativações intermediárias do LLM, a intervenção causal pode ser realizada simplesmente adicionando o vetor decodificador às ativações do modelo. A força desta intervenção pode ser ajustada multiplicando este vetor decodificador por um fator de espalhamento. Quando os pesquisadores da Antrópico adicionaram o vetor decodificador SAE "Golden Gate Bridge" à ativação de Claude, Claude foi forçado a mencionar "Golden Gate Bridge" em todas as respostas.

Abaixo está uma implementação de referência de uma intervenção causal usando o recurso hipotético 317. Semelhante ao "Golden Gate Bridge" Claude, esta intervenção muito simples força o modelo GPT-3 a mencionar "golden retriever" em todas as respostas.

def perform_intervention (model_activations_D: tocha.Tensor, decodificador_FD: tocha.Tensor, escala: float) -> tocha.Tensor:

intervenção_vetor_D = decodificador_FD [317, :]

scaled_intervention_vector_D = vetor_intervenção_D * escala

ativações_do_modelo_modificado_D = ativações_do_modelo_D + vetor_de_intervenção_em_escala_D

retornar modified_model_activations_D

O dilema da avaliação de autoencoders esparsos

Um dos grandes desafios do uso da SAE é a avaliação. Podemos treinar autoencoders esparsos para interpretar modelos de linguagem, mas não temos nenhuma verdade subjacente mensurável das representações de linguagem natural. Atualmente, a avaliação é muito subjetiva, basicamente “estudamos a entrada de ativação de uma série de recursos e depois explicamos intuitivamente a interpretabilidade desses recursos”. Esta é a principal limitação do campo de interpretabilidade.

Os pesquisadores descobriram alguns proxies comuns que parecem corresponder à interpretabilidade dos recursos. Os mais comumente usados ​​são L0 e Perda Recuperada. L0 é o número médio de elementos diferentes de zero na representação intermediária codificada do SAE. A perda recuperada substitui as ativações originais do GPT por ativações reconstruídas e mede a perda adicional de resultados de reconstrução imperfeitos. Geralmente há uma compensação entre essas duas métricas, pois a SAE pode escolher uma solução que leve a uma diminuição na precisão da reconstrução, a fim de melhorar a dispersão.

Ao comparar SAEs, uma abordagem comum é representar graficamente as duas variáveis ​​e depois examinar as compensações entre elas. Para obter melhores compensações, muitos novos métodos SAE (como Gated SAE da DeepMind e TopK SAE da OpenAI) modificaram a penalidade de dispersão. A imagem abaixo é do artigo Gated SAE da DeepMind. O Gated SAE é representado pela linha vermelha, localizada no canto superior esquerdo do gráfico, o que mostra que ele tem melhor desempenho nesse trade-off.



Gated SAE L0 e perda recuperada

Existem vários níveis de dificuldade na mensuração da SAE. L0 e Perda Recuperada são dois indicadores proxy. No entanto, não os usamos durante o treinamento porque L0 não é diferenciável e calcular a perda recuperada durante o treinamento SAE é muito caro computacionalmente. Em vez disso, nossa perda de treinamento é determinada por um termo de penalidade L1 e pela precisão da reconstrução de ativações internas, em vez de seu impacto na perda posterior.

A função de perda de treinamento não corresponde diretamente à métrica substituta, e a métrica substituta é apenas uma proxy para uma avaliação subjetiva da interpretabilidade do recurso. Dado que o nosso verdadeiro objectivo é “compreender como o modelo funciona” e as avaliações subjectivas da interpretabilidade são apenas um substituto, haverá outra camada de incompatibilidade. Alguns conceitos importantes no LLM podem não ser fáceis de interpretar, e podemos ignorar esses conceitos enquanto otimizamos cegamente a interpretabilidade.

Resumir

O campo da explicabilidade ainda tem um longo caminho a percorrer, mas a SAE é um verdadeiro progresso. SAE permite novas aplicações interessantes, como um método não supervisionado para encontrar vetores de direção, como o vetor de direção da Ponte Golden Gate. SAE também pode nos ajudar a encontrar loops em modelos de linguagem com mais facilidade, o que pode ser usado para remover vieses desnecessários dentro do modelo.

O facto de os SAEs poderem encontrar características interpretáveis ​​(mesmo que o objectivo seja simplesmente identificar padrões nas activações) sugere que podem revelar algo significativo. Há também evidências de que o LLM pode realmente aprender algo significativo, em vez de apenas memorizar padrões estatísticos superficiais.

A SAE também poderia representar um marco inicial que empresas como a Anthropic almejavam, ou seja, "MRI (ressonância magnética) para modelos de aprendizado de máquina". A SAE ainda não proporciona um entendimento perfeito, mas pode ser usada para detectar mau comportamento. Os grandes desafios da SAE e da avaliação da SAE não são intransponíveis e muitos pesquisadores já trabalham neste tema.

Para obter mais informações sobre autoencoders esparsos, consulte o notebook Colab de Callum McDougal: https://www.lesswrong.com/posts/LnHowHgmrMbWtpkxx/intro-to-superposition-and-sparse-autoencoders-colab

https://www.reddit.com/r/MachineLearning/comments/1eeihdl/d_an_intuitive_explanation_of_sparse_autoencoders/

https://adamkarvonen.github.io/machine_learning/2024/06/11/sae-intuitions.html