Retropropagação gradiente através de conexões de salto ResNet

22

Estou curioso para saber como os gradientes são propagados novamente através de uma rede neural usando módulos ResNet / pular conexões. Eu já vi algumas perguntas sobre o ResNet (por exemplo, rede neural com conexões de camada de salto ), mas esta pergunta especificamente sobre a propagação de retorno de gradientes durante o treinamento.

A arquitetura básica está aqui:

insira a descrição da imagem aqui

Li este artigo, Estudo de redes residuais para reconhecimento de imagens , e na Seção 2 eles falam sobre como um dos objetivos do ResNet é permitir um caminho mais curto / claro para o gradiente se propagar novamente para a camada base.

Alguém pode explicar como o gradiente está fluindo através desse tipo de rede? Não entendo bem como a operação de adição e a falta de uma camada parametrizada após a adição permitem uma melhor propagação do gradiente. Tem algo a ver com a forma como o gradiente não muda ao fluir através de um operador add e é de alguma forma redistribuído sem multiplicação?

Além disso, eu posso entender como o problema do gradiente de fuga é aliviado se o gradiente não precisar fluir através das camadas de peso, mas se não houver fluxo de gradiente nos pesos, como eles serão atualizados após a passagem para trás?

Simon
fonte
Apenas uma pergunta idiota: por que passamos x como pular conexão e não calcula inversa (F (x)) para obter x no final? Isso é causa de complexidade computacional?
usar o seguinte
Eu não entendi seu ponto the gradient doesn't need to flow through the weight layers, você poderia explicar isso?
anu

Respostas:

13

Adicionar envia o gradiente de volta igualmente para ambas as entradas. Você pode se convencer disso executando o seguinte no tensorflow:

import tensorflow as tf

graph = tf.Graph()
with graph.as_default():
    x1_tf = tf.Variable(1.5, name='x1')
    x2_tf = tf.Variable(3.5, name='x2')
    out_tf = x1_tf + x2_tf

    grads_tf = tf.gradients(ys=[out_tf], xs=[x1_tf, x2_tf])
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        fd = {
            out_tf: 10.0
        }
        print(sess.run(grads_tf, feed_dict=fd))

Saída:

[1.0, 1.0]

Portanto, o gradiente será:

  • retornado às camadas anteriores, inalterado, via conexão skip-layer e também
  • passado para o bloco com pesos e usado para atualizar esses pesos

Edit: existe uma pergunta: "qual é a operação no ponto em que a conexão da rodovia e o bloco da rede neural se unem novamente, na parte inferior da Figura 2?"

A resposta é: eles são somados. Você pode ver isso na fórmula da Figura 2:

outputF(x)+x

O que isso diz é que:

  • os valores no barramento ( )x
  • são adicionados aos resultados da passagem dos valores do barramento, , pela rede, ou seja,xF(x)
  • para fornecer a saída do bloco residual, que eu rotulei aqui comooutput

Edição 2:

Reescrevendo com palavras ligeiramente diferentes:

  • na direção para frente, os dados de entrada fluem pelo barramento
    • em pontos ao longo do barramento, blocos residuais podem aprender a adicionar / remover valores ao vetor de barramento
  • na direção inversa, os gradientes fluem de volta pelo ônibus
    • ao longo do caminho, os gradientes atualizam os blocos residuais pelos quais passam
    • os blocos residuais irão modificar os gradientes levemente demais

Os blocos residuais modificam os gradientes que fluem para trás, mas não há funções de 'esmagamento' ou 'ativação' pelas quais os gradientes fluem. As funções 'squashing' / 'activation' são o que causa o problema do gradiente de explosão / desaparecimento; portanto, removendo-as do próprio barramento, mitigamos esse problema consideravelmente.

Editar 3: Pessoalmente, imagino uma ressnet na minha cabeça como o diagrama a seguir. É topologicamente idêntico à figura 2, mas mostra com mais clareza, talvez, como o barramento flui direto através da rede, enquanto os blocos residuais apenas clicam nos valores e adicionam / removem algum pequeno vetor no barramento:

insira a descrição da imagem aqui

Hugh Perkins
fonte
1
se o gradiente também está sendo passado pelos blocos de peso (como nas redes regulares), de onde vem o benefício da ressnet? Com certeza, ele permite que o gradiente pule diretamente para a entrada base, mas como isso oferece um aumento de desempenho quando o outro caminho ainda é treinado normalmente?
21417 Simon
3
Entendo. Portanto, um gradiente volta diretamente para x, o outro se propaga através dos pesos de volta para x. eles são resumidos quando atingem x devido a x ter se dividido em 2 caminhos? Nesse caso, o gradiente ainda não está mudando à medida que volta através dessas camadas?
Simon
1
Os gradientes fluem por toda a pilha, inalterados. No entanto, cada bloco contribui com suas próprias alterações de gradiente na pilha, após aplicar suas atualizações de peso e gerar seu próprio conjunto de gradientes. Cada bloco possui entrada e saída, e os gradientes fluirão para fora da entrada, retornando à "estrada" do gradiente.
Hugh Perkins
1
O @RonakAgrawal adicionou uma edição mostrando a soma da operação da Figura 2 e explicando-a
Hugh Perkins
1
acrescentou uma segunda edição reformular a minha explicação um pouco :)
Hugh Perkins