.. _sec_deep_rnn: Redes neurais recorrentes profundas =================================== Até agora, discutimos apenas RNNs com uma única camada oculta unidirecional. Nele, a forma funcional específica de como as variáveis latentes e as observações interagem é bastante arbitrária. Este não é um grande problema, desde que tenhamos flexibilidade suficiente para modelar diferentes tipos de interações. Com uma única camada, no entanto, isso pode ser bastante desafiador. No caso dos modelos lineares, corrigimos esse problema adicionando mais camadas. Em RNNs, isso é um pouco mais complicado, pois primeiro precisamos decidir como e onde adicionar não linearidade extra. Na verdade, poderíamos empilhar várias camadas de RNNs umas sobre as outras. Isso resulta em um mecanismo flexível, devido à combinação de várias camadas simples. Em particular, os dados podem ser relevantes em diferentes níveis da pilha. Por exemplo, podemos querer manter disponíveis dados de alto nível sobre as condições do mercado financeiro (bear ou bull market), ao passo que em um nível mais baixo registramos apenas dinâmicas temporais de curto prazo. Além de toda a discussão abstrata acima provavelmente é mais fácil entender a família de modelos em que estamos interessados revisando :numref:`fig_deep_rnn`. Ele descreve um RNN profundo com :math:`L` camadas ocultas. Cada estado oculto é continuamente passado para a próxima etapa da camada atual e para a etapa atual da próxima camada. .. _fig_deep_rnn: .. figure:: ../img/deep-rnn.svg Arquitetura de RNN profunda. Dependência Funcional --------------------- Podemos formalizar o dependências funcionais dentro da arquitetura profunda de :math:`L` camadas ocultas representado em :numref:`fig_deep_rnn`. Nossa discussão a seguir se concentra principalmente em o modelo vanilla RNN, mas também se aplica a outros modelos de sequência. Suponha que temos uma entrada de minibatch :math:`\mathbf{X}_t \in \mathbb{R}^{n \times d}` (número de exemplos: :math:`n`, número de entradas em cada exemplo: :math:`d`) no passo de tempo :math:`t`. Ao mesmo tempo, deixar o estado oculto da camada oculta :math:`l^\mathrm{th}` ($ l = 1, ldots, L $) é :math:`l=1,\ldots,L`) é :math:`\mathbf{H}_t^{(l)} \in \mathbb{R}^{n \times h}` (número de unidades ocultas: :math:`h`) e a variável da camada de saída é :math:`\mathbf{O}_t \in \mathbb{R}^{n \times q}` (número de saídas: :math:`q`). Configurando :math:`\mathbf{H}_t^{(0)} = \mathbf{X}_t`, o estado oculto de a camada oculta :math:`l^\mathrm{th}` que usa a função de ativação :math:`\phi_l` é expresso da seguinte forma: .. math:: \mathbf{H}_t^{(l)} = \phi_l(\mathbf{H}_t^{(l-1)} \mathbf{W}_{xh}^{(l)} + \mathbf{H}_{t-1}^{(l)} \mathbf{W}_{hh}^{(l)} + \mathbf{b}_h^{(l)}), :label: eq_deep_rnn_H onde os pesos :math:`\mathbf{W}_{xh}^{(l)} \in \mathbb{R}^{h \times h}` e :math:`\mathbf{W}_{hh}^{(l)} \in \mathbb{R}^{h \times h}`, junto com o viés :math:`\mathbf{b}_h^{(l)} \in \mathbb{R}^{1 \times h}`, são os parâmetros do modelo de a camada oculta :math:`l^\mathrm{th}`. No fim, o cálculo da camada de saída é baseado apenas no estado oculto da camada oculta final :math:`L^\mathrm{th}`: .. math:: \mathbf{O}_t = \mathbf{H}_t^{(L)} \mathbf{W}_{hq} + \mathbf{b}_q, onde o peso :math:`\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}` e o viés :math:`\mathbf{b}_q \in \mathbb{R}^{1 \times q}` são os parâmetros do modelo da camada de saída. Assim como acontece com os MLPs, o número de camadas ocultas :math:`L` e o número de unidades ocultas :math:`h` são hiperparâmetros. Em outras palavras, eles podem ser ajustados ou especificados por nós. Além disso, podemos facilmente obter um RNN com portas profundas substituindo o cálculo do estado oculto em :eq:`eq_deep_rnn_H` com aquele de um GRU ou um LSTM. Implementação Concisa --------------------- Felizmente, muitos dos detalhes logísticos necessários para implementar várias camadas de um RNN estão prontamente disponíveis em APIs de alto nível. Para manter as coisas simples, apenas ilustramos a implementação usando essas funcionalidades integradas. Tomemos um modelo LSTM como exemplo. O código é muito semelhante ao que usamos anteriormente em :numref:`sec_lstm`. Na verdade, a única diferença é que especificamos o número de camadas explicitamente, em vez de escolher o padrão de uma única camada. Como de costume, começamos carregando o conjunto de dados. .. raw:: html