Redes Residuais (ResNets)
O que são Redes Residuais (ResNets)?
Redes Residuais (ResNets) são arquiteturas de redes neurais profundas construídas a partir de conexões residuais (skip connections) — atalhos que permitem que ativações (e gradientes) fluam ao redor de uma ou mais camadas. As ResNets foram introduzidas para tornar muito profundas as Redes Neurais Convolucionais treináveis de forma confiável, abordando problemas de otimização que aparecem ao empilhar muitas camadas.
Uma ResNet ainda é “apenas” uma rede profunda, mas, em vez de cada bloco aprender uma transformação completa, ela aprende um resíduo — uma mudança no input — e então adiciona essa mudança de volta ao input original.
Na forma mais simples, um bloco residual calcula:
[ \mathbf{y} = \mathbf{x} + F(\mathbf{x}) ]
- (\mathbf{x}): a entrada do bloco (o “caminho de atalho”)
- (F(\mathbf{x})): uma pequena pilha de camadas (o “ramo residual”)
- (\mathbf{y}): a saída do bloco
Essa mudança aparentemente pequena tem grandes consequências para a dinâmica de otimização, especialmente em redes profundas treinadas com Descida do Gradiente e Retropropagação.
As ResNets se tornaram um backbone padrão para tarefas de visão (classificação, detecção, segmentação) e também influenciaram arquiteturas modernas além de CNNs — mais notavelmente, conexões residuais são um componente central da Arquitetura Transformer.
Por que redes profundas “simples” são difíceis de treinar
Antes das ResNets, uma observação comum era:
- Gradientes que desaparecem/explodem podem tornar o aprendizado instável em redes muito profundas.
- Mesmo quando os gradientes são controlados (por exemplo, com melhor inicialização e normalização), surge um novo problema: o problema de degradação.
O problema de degradação (não é overfitting)
À medida que a profundidade aumenta em uma rede “simples” (uma pilha simples de camadas), o erro de treinamento pode piorar, mesmo que um modelo mais profundo devesse, em princípio, representar pelo menos uma solução tão boa quanto um mais raso.
Intuitivamente, se você adiciona camadas a uma boa rede, as camadas adicionadas poderiam aprender um mapeamento identidade e não prejudicar o desempenho. Mas, na prática, parametrizações padrão tornam difícil para o SGD descobrir esse comportamento semelhante à identidade, então a otimização fica mais difícil com a profundidade.
As ResNets atacam esse problema diretamente ao tornar o mapeamento identidade fácil.
Ideia central: aprender resíduos em vez de mapeamentos completos
Um bloco residual é projetado para que o melhor caso de “não fazer nada” seja simples:
- Se (F(\mathbf{x}) = 0), então (\mathbf{y} = \mathbf{x}) (identidade).
- O bloco só precisa aprender desvios da identidade.
Isso desloca o problema de aprendizado de “aprender uma transformação completa” para “aprender uma pequena correção”. Empiricamente, isso torna a otimização dramaticamente mais fácil à medida que a profundidade aumenta.
Fluxo de gradiente através de uma conexão de atalho
Seja (\mathbf{y} = \mathbf{x} + F(\mathbf{x})). Durante a retropropagação, o gradiente em relação a (\mathbf{x}) é:
\[ \frac{\partial \mathcal{L}}{\partial \mathbf{x}}
\frac{\partial \mathcal{L}}{\partial \mathbf{y}} \left(\mathbf{I} + \frac{\partial F}{\partial \mathbf{x}}\right) ]
O termo-chave é o componente identidade (\mathbf{I}). Mesmo que (\frac{\partial F}{\partial \mathbf{x}}) fique pequeno (ou ruidoso), ainda existe um caminho direto para os gradientes fluírem para trás. Isso ajuda a lidar com gradientes que desaparecem e torna modelos profundos mais treináveis.
Mapeamentos identidade como uma “âncora” de otimização
Outra visão prática: blocos residuais incentivam a rede a se comportar como uma função identidade na inicialização (ou, pelo menos, perto disso) e, então, aprender gradualmente refinamentos úteis. Isso frequentemente leva a:
- paisagens de perda mais suaves (na prática),
- treinamento mais estável em maiores profundidades,
- melhor escalabilidade de profundidade sem precisar de truques exóticos.
Os designs canônicos de blocos ResNet
As ResNets vêm em uma família de tipos de blocos padrão, escolhidos com base em profundidade e restrições de computação.
Bloco residual básico (ResNet-18 / ResNet-34)
Usado em ResNets mais rasas (por exemplo, 18 e 34 camadas). O ramo residual tipicamente tem duas convoluções 3×3:
- Conv(3×3) → BN → ReLU
- Conv(3×3) → BN
- Add skip → ReLU (no design original “pós-ativação”)
Quando as formas de entrada e saída coincidem, o atalho é apenas identidade.
Quando as formas não coincidem: atalhos por projeção
Se um bloco muda:
- o número de canais, ou
- a resolução espacial (via stride > 1),
então (\mathbf{x}) e (F(\mathbf{x})) não podem ser somados diretamente. Uma correção comum é um atalho por projeção, geralmente uma convolução 1×1 (frequentemente com stride):
[ \mathbf{y} = W_s \mathbf{x} + F(\mathbf{x}) ]
onde (W_s) é uma projeção linear aprendida (implementada como conv1×1 + normalização).
Isso também é como as ResNets fazem downsampling entre estágios (por exemplo, de mapas de características 56×56 para 28×28).
Blocos bottleneck (ResNet-50 / 101 / 152)
Para modelos mais profundos, o custo de empilhar muitas convoluções 3×3 se torna alto. Por isso, as ResNets usam um design gargalo (bottleneck) para reduzir computação mantendo poder representacional:
- conv 1×1: reduzir canais (compressão)
- conv 3×3: processamento espacial (a parte cara)
- conv 1×1: expandir canais de volta
Um bottleneck típico usa um fator de expansão (frequentemente 4×), por exemplo:
- canais de entrada: 256
- gargalo: 64
- canais de saída: 256
Isso gera alta acurácia com FLOPs razoáveis, motivo pelo qual a ResNet-50 é um backbone padrão tão comum na prática.
ResNets de pós-ativação vs pré-ativação
“Pós-ativação” original (ResNet v1)
No design original, o padrão era aproximadamente:
- Conv → BN → ReLU
- Conv → BN
- Add shortcut
- ReLU
Isso funciona bem, mas pesquisadores encontraram uma formulação ainda melhor para otimização em profundidades muito altas.
Pré-ativação (ResNet v2)
ResNets de pré-ativação (pre-activation ResNets) movem normalização e ativação antes das convoluções:
- BN → ReLU → Conv
- BN → ReLU → Conv
- Add shortcut (frequentemente sem ReLU imediatamente após)
Por que isso ajuda:
- O caminho de atalho se torna um mapeamento identidade mais “limpo” (menos interferência de não linearidades).
- Gradientes podem se propagar mais diretamente pelos caminhos identidade.
- Redes muito profundas (100+ camadas) frequentemente treinam de forma mais confiável.
Na prática, muitas implementações modernas preferem o estilo de pré-ativação (ou pelo menos adotam princípios de ordenação relacionados), especialmente ao experimentar profundidade.
BatchNorm e ResNets: como elas interagem
A Normalização por Lotes (BN) está fortemente associada às ResNets, e a maioria das variantes canônicas de ResNet inclui BN em cada camada convolucional.
Por que BN é útil em ResNets
- estabiliza distribuições de ativação entre camadas,
- permite taxas de aprendizado maiores,
- melhora o condicionamento do problema de otimização.
Notas práticas sobre BN
- Tamanhos de lote pequenos (comuns em detecção/segmentação) podem tornar as estatísticas de BN ruidosas. Soluções típicas:
- “Freeze BN” (usar estatísticas acumuladas, não atualizar) durante fine-tuning,
- usar BN sincronizada entre GPUs,
- substituir BN por variantes de GroupNorm/LayerNorm (dependendo da tarefa).
- Se você carregar um backbone ResNet pré-treinado, tenha atenção ao modo de BN:
model.train()atualiza as estatísticas de BN,model.eval()usa as estatísticas acumuladas armazenadas.
Juntando tudo: como é uma ResNet
As ResNets geralmente são organizadas em estágios. Cada estágio mantém a resolução espacial constante e aumenta a contagem de canais; entre estágios, a resolução espacial é reduzida (stride 2) e os canais aumentam.
Um stem típico de ResNet:
- conv 7×7 stride 2, depois maxpool stride 2 (estilo ImageNet), então estágios como:
- Estágio 1: muitos blocos residuais em 56×56
- Estágio 2: blocos em 28×28
- Estágio 3: blocos em 14×14
- Estágio 4: blocos em 7×7
- Global average pooling → classificador linear
Para imagens menores (por exemplo, CIFAR-10), é comum usar um stem menor (conv 3×3, sem maxpool).
Exemplo prático: um bloco residual mínimo (PyTorch)
Abaixo está um “bloco básico” simplificado ilustrando o padrão residual e o atalho por projeção.
import torch
import torch.nn as nn
import torch.nn.functional as F
class BasicResidualBlock(nn.Module):
def __init__(self, in_ch, out_ch, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_ch, out_ch, 3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_ch)
self.conv2 = nn.Conv2d(out_ch, out_ch, 3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_ch)
# Projection if shape changes
self.proj = None
if stride != 1 or in_ch != out_ch:
self.proj = nn.Sequential(
nn.Conv2d(in_ch, out_ch, 1, stride=stride, bias=False),
nn.BatchNorm2d(out_ch)
)
def forward(self, x):
identity = x
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
if self.proj is not None:
identity = self.proj(identity)
out = F.relu(out + identity)
return out
Em implementações reais de ResNet, você também verá:
- blocos gargalo,
- ordenação de pré-ativação,
- inicialização cuidadosa (veja abaixo),
- helpers de construção de estágios para empilhar blocos.
Inicialização e truques de “zero-gamma”
Um detalhe prático útil: muitas implementações de ResNet inicializam a BN final em cada ramo residual para que o resíduo comece perto de zero. Isso faz com que os blocos inicialmente se comportem como mapeamentos identidade.
Abordagem comum:
- definir o parâmetro de escala (\gamma) da última BN em um bloco como 0 na inicialização.
Efeito:
- No início do treinamento, (F(\mathbf{x}) \approx 0), então a rede se comporta como um modelo raso semelhante à identidade.
- A otimização começa em um regime estável e aprende resíduos progressivamente.
Muitos codebases de produção incluem isso porque pode melhorar a estabilidade e, às vezes, a acurácia.
Variantes e extensões comuns de ResNet
ResNet é mais um padrão do que uma única arquitetura. Várias variantes populares modificam largura, cardinalidade ou conectividade preservando a ideia central residual.
Wide ResNets
Em vez de ficar mais profunda, aumente a largura da rede (mais canais por camada). Wide ResNets frequentemente:
- treinam mais rápido,
- atingem forte acurácia em profundidade moderada,
- são comuns em benchmarks de imagens menores.
ResNeXt
Adiciona o conceito de cardinalidade (cardinality) (múltiplas transformações agrupadas em paralelo) dentro do ramo residual — de maneira vagamente semelhante ao “split-transform-merge”. Frequentemente oferece melhores trade-offs de acurácia/compute do que simplesmente aumentar profundidade ou largura.
Profundidade Estocástica (Stochastic Depth) / DropPath
Remove aleatoriamente ramos residuais inteiros durante o treinamento (o caminho de atalho permanece). Isso:
- regulariza redes muito profundas,
- reduz a profundidade efetiva por iteração,
- pode melhorar a generalização.
Conexões densas vs conexões residuais
Arquiteturas como DenseNet usam concatenação densa em vez de atalhos aditivos; elas compartilham motivações (fluxo de gradiente, reutilização de características), mas se comportam de forma diferente em memória/computação. As ResNets continuam mais comuns como backbones de uso geral.
Por que ResNets funcionam: múltiplas perspectivas complementares
As ResNets têm várias “explicações”, nenhuma das quais é a história completa por si só, mas juntas esclarecem por que conexões residuais são tão eficazes.
1) Reparametrização torna a otimização mais fácil
Aprender (H(\mathbf{x})) diretamente pode ser mais difícil do que aprender (F(\mathbf{x}) = H(\mathbf{x}) - \mathbf{x}). Se a função desejada está próxima da identidade (frequentemente verdadeiro localmente em hierarquias profundas de características), aprendizado residual é um problema com melhor condicionamento.
2) Conexões de atalho criam caminhos curtos de gradiente
Mesmo que a rede seja profunda, gradientes podem alcançar camadas iniciais por muitas rotas curtas. Isso melhora a otimização com Retropropagação, especialmente quando combinado com normalização.
3) Comportamento semelhante a ensemble (visão informal)
Como a informação pode contornar alguns blocos, a rede se comporta um pouco como um ensemble implícito de caminhos de diferentes comprimentos. Isso não é um ensemble estrito, mas ajuda a explicar robustez e treinabilidade.
4) Intuição de sistemas dinâmicos / EDO
Uma rede residual profunda pode ser vista como atualizando iterativamente características:
[ \mathbf{x}_{t+1} = \mathbf{x}_t + F(\mathbf{x}_t) ]
Isso se assemelha a uma discretização de Euler direto de um sistema dinâmico em tempo contínuo. Essa visão inspirou trabalhos de “neural ODE” e ajuda a construir intuição: blocos residuais são como pequenos passos incrementais em vez de remapeamentos completos.
Onde ResNets são usadas na prática
Backbones para classificação de imagens
ResNet-18/34 são comuns quando computação é limitada; ResNet-50 é um padrão; ResNet-101/152 aparecem quando acurácia é priorizada e a computação permite.
Casos de uso típicos:
- classificação de imagens de produtos,
- baselines em imagens médicas,
- fine-tuning de backbones pré-treinados em conjuntos de dados de domínio.
Detecção e segmentação
Backbones residuais combinam bem com pirâmides de características multi-escala e são amplamente usados em:
- detecção de objetos (por exemplo, sistemas no estilo Faster R-CNN),
- segmentação de instâncias/semântica (por exemplo, sistemas no estilo Mask R-CNN).
(Frameworks modernos de detecção frequentemente substituem por backbones mais novos, mas ResNets continuam sendo um baseline forte.)
Aprendizado por transferência (transfer learning)
ResNets pré-treinadas no ImageNet são frequentemente usadas como extratoras de características:
- congelar camadas iniciais, treinar uma nova cabeça,
- ou fazer fine-tuning end-to-end com uma taxa de aprendizado menor.
Dica prática: ao fazer fine-tuning com lotes pequenos, considere o manejo de BN (congelar ou sincronizar), como observado acima.
Além de CNNs: conexões residuais em todo lugar
Conexões residuais agora são um princípio geral de design:
- Transformers usam conexões residuais ao redor de subcamadas de atenção e MLP.
- Muitas arquiteturas profundas de MLP e backbones modernos de visão incorporam caminhos residuais.
Então, mesmo que você não esteja usando uma “ResNet” propriamente dita, é provável que esteja usando a ideia residual.
Notas práticas de uso e armadilhas
Escolhendo uma variante de ResNet
- ResNet-18/34: boas para conjuntos de dados menores, iteração mais rápida, dispositivos de borda.
- ResNet-50: ponto de equilíbrio comum para aprendizado por transferência e backbones gerais de visão.
- ResNet-101+: quando você tem dados/computação suficientes e precisa de maior acurácia.
Se você está limitado por computação, considere:
- uma profundidade menor,
- ou uma variante mais larga porém mais rasa (Wide ResNet),
- ou usar backbones eficientes modernos (dependendo do seu stack).
Taxa de aprendizado e otimização
ResNets tipicamente funcionam bem com:
- SGD + momentum (clássico),
- AdamW em alguns cenários (especialmente fora de receitas clássicas de ImageNet).
BN frequentemente permite taxas de aprendizado maiores, mas se você remover BN ou usar lotes pequenos, pode precisar reajustar:
- taxa de aprendizado,
- warmup,
- weight decay,
- escolha de normalização.
Não assuma que “mais profundo é sempre melhor”
Mesmo com conexões residuais, modelos muito profundos podem:
- sofrer overfitting em conjuntos de dados pequenos,
- ser mais lentos e mais difíceis de implantar,
- apresentar retornos decrescentes em comparação com largura ou melhores técnicas de aumento de dados (augmentation).
Trate profundidade, largura, tamanho de dados e augmentation como um problema de design equilibrado.
Fique atento à “dominância” do atalho
Em alguns contextos (especialmente se ramos residuais forem inicializados de forma fraca ou regularizados em excesso), a rede pode depender fortemente dos atalhos no início do treinamento. Isso geralmente é aceitável, mas se o aprendizado estagnar, considere:
- schedule de taxa de aprendizado,
- capacidade do ramo residual (largura),
- garantir que BN e inicialização estejam corretas,
- verificar se atalhos por projeção estão sendo usados quando as formas mudam.
Resumo
Redes Residuais (ResNets) são arquiteturas profundas construídas a partir de blocos residuais que adicionam um atalho identidade a uma transformação aprendida:
- Elas abordam problemas de otimização em CNNs profundas, incluindo o problema de degradação.
- Conexões de atalho melhoram o fluxo de gradiente e tornam mapeamentos identidade fáceis de representar.
- Variantes-chave incluem blocos básicos, blocos gargalo, e ResNets de pré-ativação.
- Componentes como BatchNorm são comumente usados e interagem fortemente com a estabilidade do treinamento (especialmente com considerações de tamanho de lote).
- ResNets continuam fundamentais em visão computacional e a ideia residual agora sustenta muitas arquiteturas modernas, incluindo Transformers e Transformers de Visão (ViT).
Se você está construindo ou fazendo fine-tuning de um modelo de visão hoje, as ResNets ainda são um dos melhores backbones “padrão” para entender — tanto como ferramenta prática quanto como um template conceitual para design de redes profundas.