LABORATÓRIO 06 · ARQUITETURA CONFIGURÁVEL
Monte uma rede e acompanhe o backpropagation.
Escolha de 1 a 10 entradas, as camadas ocultas e até 4 saídas. O laboratório cria dados sintéticos, treina a rede e abre cada etapa matemática do aprendizado.
ocultas→saídas
1 · MONTE A ARQUITETURA
Quantos sinais e neurônios a rede terá?
Alterar a arquitetura cria uma rede nova. Os pesos começam com valores pequenos e aleatórios.
A rede que você montou
Cada linha é um peso. Azul representa peso positivo; laranja, negativo.
Erro durante o treinamento
O eixo x mostra as épocas; o eixo y mostra a entropia cruzada média.
3 · ABRA UMA AMOSTRA
Veja os números percorrendo a rede
u = Σ(wx) + bE = −1/m Σ[y ln(ŷ) + (1−y)ln(1−ŷ)]δˡ = (Wˡ⁺¹)ᵀδˡ⁺¹ ⊙ g′(uˡ)w ← w − ηδaPor que isso é backpropagation? O erro nasce nas saídas. Em seguida, a regra da cadeia calcula quanto cada neurônio anterior contribuiu para esse erro. Os deltas caminham da direita para a esquerda; depois, os pesos são corrigidos.
4 · RESULTADO AMOSTRA POR AMOSTRA
Tabela adaptada à arquitetura
Para cada saída aparecem o alvo y, a previsão contínua ŷ e o erro com sinal e = y − ŷ. Verde indica decisão correta; vermelho, incorreta. O custo E resume todas as saídas da amostra.
COMO O DATASET FAKE É CRIADO?
Há uma regra escondida por trás dos alvos.
O laboratório sorteia 16 exemplos com valores entre 0 e 1. Para cada saída, combina as entradas com coeficientes fixos e uma interação entre duas características. A mediana divide os resultados em 0 e 1, evitando um conjunto formado quase só por uma classe. A rede vê apenas as entradas e os alvos: ela precisa aproximar essa regra ajustando seus próprios pesos.
CÓDIGO COMPLETO E EXECUTÁVEL
Configure, treine, avalie e use a rede
O exemplo usa matrizes, arrays e laços for. Além do forward e do backpropagation, há dataset, épocas, custo, previsão e avaliação.
// Quantidade de neurônios em cada camada: 3 entradas, 4 ocultos e 2 saídas.
var tamanhos = [3, 4, 2];
var pesos = [];
var biases = [];
// As saídas usam one-hot: classe A = [1,0] e classe B = [0,1].
var dados = [
[[0,0,0], [1,0]], [[0,0,1], [1,0]],
[[0,1,0], [1,0]], [[1,0,0], [1,0]],
[[0,1,1], [0,1]], [[1,0,1], [0,1]],
[[1,1,0], [0,1]], [[1,1,1], [0,1]]
];
// A função Sigmoid será usada nas camadas ocultas e na saída.
function sigmoid(u) {
return 1 / (1 + Math.exp(-u));
}
// Sua derivada pode ser calculada com a própria ativação a.
function derivadaSigmoid(a) {
return a * (1 - a);
}
// Cria uma matriz de pesos para cada par de camadas.
function criarRede() {
for (var camada = 1; camada < tamanhos.length; camada++) {
pesos[camada - 1] = [];
biases[camada - 1] = [];
for (var neuronio = 0; neuronio < tamanhos[camada]; neuronio++) {
pesos[camada - 1][neuronio] = [];
biases[camada - 1][neuronio] = Math.random() - 0.5;
for (var entrada = 0; entrada < tamanhos[camada - 1]; entrada++) {
pesos[camada - 1][neuronio][entrada] = Math.random() - 0.5;
}
}
}
}
// Calcula todas as ativações, da entrada até a saída.
function forward(entrada) {
var ativacoes = [entrada];
for (var camada = 0; camada < pesos.length; camada++) {
var proximaAtivacao = [];
for (var neuronio = 0; neuronio < pesos[camada].length; neuronio++) {
var u = biases[camada][neuronio];
for (var anterior = 0; anterior < ativacoes[camada].length; anterior++) {
u = u + pesos[camada][neuronio][anterior] * ativacoes[camada][anterior];
}
proximaAtivacao[neuronio] = sigmoid(u);
}
ativacoes[camada + 1] = proximaAtivacao;
}
return ativacoes;
}
// Calcula primeiro o delta da saída e depois volta pelas camadas ocultas.
function calcularDeltas(ativacoes, alvo) {
var deltas = [];
var ultima = pesos.length - 1;
deltas[ultima] = [];
for (var saida = 0; saida < alvo.length; saida++) {
// A divisão aparece porque o custo usa a média das saídas.
deltas[ultima][saida] =
(ativacoes[ultima + 1][saida] - alvo[saida]) / alvo.length;
}
for (var camada = ultima - 1; camada >= 0; camada--) {
deltas[camada] = [];
for (var neuronio = 0; neuronio < ativacoes[camada + 1].length; neuronio++) {
var erroQueVoltou = 0;
for (var proximo = 0; proximo < deltas[camada + 1].length; proximo++) {
erroQueVoltou = erroQueVoltou + pesos[camada + 1][proximo][neuronio] * deltas[camada + 1][proximo];
}
var a = ativacoes[camada + 1][neuronio];
deltas[camada][neuronio] = erroQueVoltou * derivadaSigmoid(a);
}
}
return deltas;
}
// Usa cada delta para corrigir pesos e bias.
function ajustarPesos(ativacoes, deltas, taxa) {
for (var camada = 0; camada < pesos.length; camada++) {
for (var neuronio = 0; neuronio < pesos[camada].length; neuronio++) {
for (var anterior = 0; anterior < pesos[camada][neuronio].length; anterior++) {
var gradiente = deltas[camada][neuronio] * ativacoes[camada][anterior];
pesos[camada][neuronio][anterior] = pesos[camada][neuronio][anterior] - taxa * gradiente;
}
biases[camada][neuronio] = biases[camada][neuronio] - taxa * deltas[camada][neuronio];
}
}
}
// Reúne as três fases do treinamento de uma amostra.
function treinarAmostra(entrada, alvo, taxa) {
var ativacoes = forward(entrada); // 1. previsão
var deltas = calcularDeltas(ativacoes, alvo); // 2. backpropagation
ajustarPesos(ativacoes, deltas, taxa); // 3. atualização
}
function calcularCusto() {
var soma = 0;
for (var i = 0; i < dados.length; i++) {
var saida = forward(dados[i][0])[pesos.length];
for (var j = 0; j < saida.length; j++) {
var erro = dados[i][1][j] - saida[j];
soma += erro * erro;
}
}
return soma / dados.length;
}
function treinar(epocas, taxa) {
for (var epoca = 0; epoca < epocas; epoca++) {
for (var i = 0; i < dados.length; i++) {
treinarAmostra(dados[i][0], dados[i][1], taxa);
}
}
}
function prever(entrada) {
var saida = forward(entrada)[pesos.length];
if (saida[0] > saida[1]) return 'A';
return 'B';
}
function avaliar() {
var acertos = 0;
for (var i = 0; i < dados.length; i++) {
var esperada = dados[i][1][0] === 1 ? 'A' : 'B';
if (prever(dados[i][0]) === esperada) acertos++;
}
return acertos / dados.length;
}
// ----------------------- USO DO MODELO -----------------------
criarRede();
console.log('Custo inicial:', calcularCusto());
treinar(5000, 0.4);
console.log('Custo final:', calcularCusto());
console.log('Acurácia:', avaliar());
console.log('Previsão para [1, 0, 1]:', prever([1, 0, 1]));