Ao trabalharmos com redes convencionais, não fornecemos nenhuma informação sobre ordem ou sequência dos tokens.
Mas sabemos que a ordem das palavras em uma frase possui significado.
Ao invés de utilizarmos camadas sequenciais que recebem uma frase inteira de uma vez podemos criar redes que recebem uma palavra por vez e se “realimentam” a cada nova palavra.
Deixamos de necessitar padding e conseguimos fornecer informação posicional sobre cada palavra através da própria arquitetura da rede.
Cada iteração é independente.
Facilmente paralelizável.
Alimentamos toda uma sequência de tokens de uma vez.
Cada iteração depende da anterior.
Sequencial por natureza, poucas oportunidades de paralelização.
Alimentamos um token de cada vez de maneira sequencial
Diversas tarefas de PLN lidam com sequências:
Tradução (Machine Translation)
Responder perguntas (Q&A)
Reconhecimento de fala (Speech Recognition)
RNN’s são capazes não somente de processar sequências como também de gerar sequências.
Uma arquitetura popular para tarefas Seq2Seq é a arquitetura Encoder Decoder.
Redes Encoder Decoder possuem 2 partes:
Uma RNN chamada encoder que recebe uma sequência de tamanho qualquer e gera um vetor C de tamanho fixo.
Uma RNN chamada decoder que recebe o vetor C e gera uma sequência de tamanho qualquer.
Redes Encoder Decoder possuem 2 partes:
Uma RNN chamada encoder que recebe uma sequência de tamanho qualquer e gera um vetor C de tamanho fixo.
Uma RNN chamada decoder que recebe o vetor C e gera uma sequência de tamanho qualquer.
Redes Encoder Decoder possuem 2 partes:
Uma RNN chamada encoder que recebe uma sequência de tamanho qualquer e gera um vetor C de tamanho fixo.
Uma RNN chamada decoder que recebe o vetor C e gera uma sequência de tamanho qualquer.
Redes Encoder Decoder possuem 2 partes:
Uma RNN chamada encoder que recebe uma sequência de tamanho qualquer e gera um vetor C de tamanho fixo.
Uma RNN chamada decoder que recebe o vetor C e gera uma sequência de tamanho qualquer.
O decoder recebe o último token gerado até prever um token especial <eos> que representa o fim de uma frase.
Possibilita a geração de um modelo neural de linguagem
\(T_x \neq T_y\) (Encoder-Decoder)
\(T_x=T_y\)
O gradiente de uma camada é calculado pela regra da cadeia e portanto é um produto do gradiente de todas as camadas anteriores.
O que acontece com uma camada se alguma das camadas anteriores possuir um gradiente muito pequeno? E se ele for muito grande?
Com um gradiente muito elevado é possível que ao realizarmos uma etapa de backpropagation tomemos um passo muito grande que gere um update ruim (aumente a Loss).
Se o passo for acima de um limite definido, nós diminuímos a magnitude do passo e mantemos a direção.
from tensorflow import keras
keras.optimizers.SGD(lr=0.01, momentum=0.9, clipnorm=1.0)O gradiente pode ser visto como uma medida da influência do passado no futuro.
Com um gradiente baixo a influência passa a ser baixa. Impossível capturar relações distantes.
Não! Toda rede profunda sofre destas questões, mas redes recorrentes são especialmente instáveis devido a utilização da mesma matriz de pesos.
Gradiente não fica saturado como \(tanh(x)\)
Conecte tudo com tudo
Também conhecidas como Skip-Connections.
São utilizadas no modelo Transformer
Normalizar ajuda a impedir que as ativações saturem ao confiná-las em uma região.
Uma inicialização muito baixa nos leva a vanishing gradient e uma inicialização muito grande nos leva a exploding gradient.
Como podemos inicializar os pesos de uma maneira apropriada?