Soluções Comentadas - Lista 2 de
Inteligência Artificial (Versão Anterior)
1. Multi Layer Perceptron (MLP)
(a)) A MLP é considerada um aproximador universal de funções porque, segundo o teorema
da aproximação universal, uma rede com ao menos uma camada oculta e função de ativação
não linear é capaz de representar qualquer função contínua sobre um domínio fechado.
Isso significa que uma MLP com número adequado de neurônios pode aproximar
qualquer função com precisão arbitrária.
(b)) A atualização dos parâmetros nas camadas intermediárias ocorre com o algoritmo de
retropropagação (backpropagation). O erro é calculado na saída, e, usando a regra da
cadeia, os gradientes são propagados para trás, permitindo ajustar os pesos em todas as
camadas.
Fórmulas derivam de:
∂E/∂w = ∂E/∂a × ∂a/∂z × ∂z/∂w
(com E: erro, a: ativação, z: pré-ativação, w: pesos)
(c)) Um perceptron simples resolve apenas problemas linearmente separáveis. O XOR não é
separável por uma única linha, portanto não pode ser resolvido com um único perceptron.
Já uma MLP com pelo menos uma camada oculta pode compor duas regiões de ativação
para simular o comportamento do XOR com sucesso.
(d)) Saída: [0,0,0,0,1,1,0,0,0,0] (duas classes com 1)
Classe verdadeira: 4 (posição 4)
Entropia cruzada:
CE = -log(p_4)
Se p_4 = 1, então CE = 0 (acerto perfeito).
Mas aqui também há p_5 = 1, indicando ambiguidade → CE > 0.
Isso implica que a rede está indecisa entre classe 4 e 5.
2. Convolução
(a)) O filtro [[1,0,-1],[1,0,-1],[1,0,-1]] é um detector de bordas verticais, bastante parecido
com o filtro de Sobel. Ele responde a mudanças na direção horizontal, destacando as
transições de intensidade entre colunas adjacentes da imagem.
Ideal para detectar contornos verticais, como bordas de objetos em fotos.
(b)) O kernel fornecido é 3x3x3 e a imagem é 4x4x3. Como stride = 1 e padding = 0, a saída
terá dimensões 2x2.
Para cada posição válida (sem ultrapassar as bordas da imagem), fazemos:
1. Multiplicação elemento a elemento entre o kernel e o bloco correspondente da imagem
2. Soma de todos os produtos
O resultado é uma matriz 2x2 com cada elemento representando uma região da imagem
filtrada pelo kernel.
(c.i)) Cada camada convolucional ou de pooling altera a dimensão da imagem. A fórmula
usada para calcular a saída de uma camada:
saída = floor((W + 2P - F)/S + 1)
Onde:
- W: tamanho da entrada
- P: padding
- F: tamanho do filtro
- S: stride
Aplicar essa fórmula para cada camada permite obter as dimensões dos feature maps.
(c.ii)) Embeddings são vetores achatados obtidos após a última camada convolucional.
Exemplo: se a última feature map tiver dimensões 6x6x256, então embedding1 = 6*6*256 =
9216 elementos.
(c.iii)) As funções de ativação (ReLU ou similares) devem ser aplicadas:
- Após cada camada convolucional
- Após cada camada totalmente conectada (fully connected)
Isso garante que a rede aprenda relações não-lineares.
(c.iv)) A dimensão de entrada entre embedding1 e embedding2 corresponde ao número de
elementos no vetor achatado (flatten) da última feature map.
(c.v)) Número de parâmetros de cada camada:
- Convolucional: (altura × largura × canais de entrada + 1) × número de filtros
- Fully connected: entradas × saídas + bias
Exemplo: (3×3×256 + 1) × 384 = 88512 parâmetros.
(c.vi)) O número total de parâmetros é a soma de todos os parâmetros de todas as camadas
convolucionais e totalmente conectadas.
Redes profundas modernas como AlexNet ou VGG podem ter dezenas de milhões de
parâmetros.
(c.vii)) Código em PyTorch (resumido):
Utilize `nn.Conv2d` para convoluções, `nn.MaxPool2d` para pooling e `nn.Linear` para as
camadas fully connected.
Modelo básico:
```python
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(...)
self.fc1 = nn.Linear(...)
def forward(self, x):
x = self.conv1(x)
...
x = self.fc1(x)
return x
```
3. Modelos de Atenção
(a)) Como as frases têm a mesma estrutura, o modelo skip-gram aprenderá embeddings
similares para 'adora', 'ama' e 'odeia', pois elas compartilham contexto idêntico ('João X
Maria').
Isso revela uma limitação dos modelos sem contexto: palavras opostas podem parecer
semanticamente próximas.
(b)) Tokens precisam de informações de posição, já que o Transformer não é sequencial. O
positional encoding adiciona vetores que codificam a posição de cada token na sequência.
Tokens próximos terão valores de encoding parecidos (em senos e cossenos) que os
distinguem ao mesmo tempo que preservam sua relação.
(c)) Tokenizadores dividem palavras em unidades menores, como subpalavras. Isso ajuda a
representar palavras semelhantes com partes comuns.
Sem tokenização, o modelo trataria 'correndo' e 'correu' como totalmente distintos,
perdendo a relação entre eles.
(d)) BPE e WordPiece tratam palavras de alta frequência como tokens inteiros. Palavras
raras são divididas em subpalavras para reduzir o vocabulário e melhorar a cobertura.
Isso equilibra compressão e capacidade de generalização.
(e)) Query × Key^T calcula a similaridade entre palavras, gerando uma matriz de atenção
bruta. Após isso, aplica-se softmax para obter os pesos de atenção.
Esses pesos indicam quanto cada palavra deve 'olhar' para as outras.
(f)) Value contém as representações que serão combinadas com os pesos de atenção. O
output da atenção é obtido multiplicando os pesos por Value.
(g)) Em cross-attention:
- Query vem do decoder (idioma de saída)
- Key e Value vêm do encoder (idioma de entrada)
Isso permite que o decoder 'preste atenção' na entrada ao gerar a saída.
(h)) Masked attention impede que um token veja tokens futuros. É usada no decoder para
geração de texto, garantindo que o modelo gere palavra por palavra corretamente.
(i)) - Encoder-decoder: tradução, resumo, perguntas e respostas
- Encoder-only: classificação, extração de entidades (ex: BERT)
- Decoder-only: geração de texto (ex: GPT)
4. Busca
(a)) Problema dos monges e canibais:
- Estado: (monges, canibais, lado do barco)
- Operadores: mover 1 ou 2 pessoas respeitando as restrições (canibais não podem ser
maioria)
- Estado final: (0, 0, direita)
Árvore de busca em largura: desenhar as configurações a partir do estado inicial até o nível
3, validando as regras a cada transição.
(b)) Busca em profundidade (DFS):
- Vai fundo em um caminho antes de voltar
- Pode não encontrar a solução ótima
- Tempo: O(b^m), Espaço: O(bm)
Busca em largura (BFS):
- Explora todos os nós em um nível antes de ir para o próximo
- Garante solução ótima (se custo uniforme)
- Tempo/Espaço: O(b^d)
(c)) Função g(n): custo acumulado até o nó n
Função h(n): estimativa do custo restante
Para o 8-puzzle:
- h1: número de peças fora do lugar
- h2: soma das distâncias de Manhattan
h2 é mais informativa e tende a gerar árvores menores.
(d)) Hill-climbing pode ficar preso em máximos locais. Reinício aleatório resolve isso
começando de vários pontos diferentes no espaço de busca.
(e)) Diferença entre A* e Hill-climbing:
- A* usa g(n) + h(n); garante solução ótima se h(n) for admissível
- Hill-climbing usa apenas h(n); não garante solução ótima
(f)) Uma heurística h(n) próxima de h*(n) (custo real ótimo) torna a busca mais eficiente e
reduz a expansão desnecessária de nós.
(g)) Jogo da velha:
- Estados: configurações do tabuleiro
- Operadores: jogadas possíveis
- Estado final: vitória, derrota ou empate
Construir árvore de busca a partir de um estado inicial.
(h)) Jogo de damas:
- Estados: posições das peças
- Operadores: movimentos e capturas
- Estado final: vitória quando o oponente não tem jogadas válidas
Construir árvore de busca baseada nas jogadas legais.
(i)) Minimax é usado para jogos de soma zero com dois jogadores. Aplica-se ao:
Jogo da velha
-
Damas
-
Sudoku e monges/canibais (não adversariais)
(j)) Construir a árvore minimax a partir do estado dado no jogo da velha, alternando
jogadas de X e O e avaliando os estados finais com +1, 0, -1.
(k)) A poda alpha-beta reduz o número de nós avaliados no algoritmo Minimax, evitando
explorar ramos que não afetam o resultado final.
(l)) Durante a poda alpha-beta:
- α (melhor valor de MAX)
- β (melhor valor de MIN)
Se β ≤ α, interrompe-se a busca no ramo atual.
Garante eficiência sem comprometer a exatidão.