Cálculo e otimização: derivadas que orientam o ajuste
Você vai implementar duas maneiras independentes de calcular a mesma derivada: fórmula analítica e diferença central. Depois treinará uma reta e a comparará com a resposta da álgebra. O laboratório funciona como uma investigação de erros: introduza uma omissão de fator, um passo grande e uma atualização fora de ordem para entender que evidência acusa cada falha.
Tente escrever a função gradient antes de consultar o código. Use a ordem [b,m] em todas as funções e mantenha os dados dentro do arquivo calculus.mjs. Nossa execução usa exemplos sintéticos com solução conhecida; ela verifica a implementação didática, sem afirmar desempenho de um otimizador em dados reais.
JavaScriptMatemáticaAo terminar esta aula
- Declare a perda antes de avaliar o gradiente.
- Diferença central e invariância da média localizam erros distintos.
- Convergência no exemplo é evidência local, não validação de generalização.
Antes de continuar: Leitura: Cálculo e otimização: derivadas que orientam o ajuste
Fixar o objetivo e conferir a conta inicial
FundamentosRegistre a definição exata: cada perda é metade do erro ao quadrado e o resultado do lote é a média. Não chame esse número apenas de erro, porque soma absoluta, soma quadrática e média quadrática medem objetos diferentes. A função loss recebe parâmetros e registros, valida dados finitos e rejeita lote vazio. Para [b,m]=[0,0], os erros dos três pedidos são −1, −2 e −2. A soma das metades dos quadrados é 0.5+2+2=4.5 e a média é 1.5. Essa expectativa manual permite verificar loss antes de usá-la para diagnosticar gradient.
Na sequência, escreva as contribuições do gradiente nessa origem: o componente de b é (−1−2−2)/3=−5/3 e o de m é (0−2−4)/3=−2. Confira as duas posições separadamente, evitando associar um resultado correto à coordenada errada. As derivadas parciais e a regra da cadeia usadas aqui retomam a base de cálculo; o exercício acrescenta a disciplina de manter o objetivo e sua implementação sob o mesmo contrato.
Construir a comparação numérica independente
FundamentosImplemente numerical copiando o vetor original em duas listas. Em uma, some h à coordenada j; na outra, subtraia h. Avalie loss e divida a diferença por 2h. Não altere theta diretamente, pois isso contaminaria a próxima coordenada e a comparação. Use o ponto [0.3,−0.2] em vez da solução final. Nesse ponto há erros não nulos e fatores de x ativos, tornando o teste capaz de detectar uma regra da cadeia incompleta. Compare cada componente com tolerância explicitada no código.
Faça a mutação experimental de retirar x da contribuição da inclinação. A diferença central deve discordar nesse ponto. Depois duplique as linhas do lote e confira que a média e o gradiente médio permanecem iguais. Essa segunda propriedade captura a omissão da divisão por n. Uma derivada pode ser proporcional à correta e ainda mover o modelo na direção útil; por isso a queda da perda sozinha seria um teste fraco. Guarde no relatório qual defeito cada verificação detecta, para não confundir execução sem erro com evidência completa de correção.
Investigar o passo e a atualização simultânea
FundamentosA função step calcula g uma única vez e cria novos parâmetros pela fórmula value−rate×g. Isso garante que ambas as coordenadas usam o mesmo estado. Execute um registro x=2,y=1 a partir de [0,0]. Com taxa 0.1, o novo vetor é [0.1,0.2], a previsão passa a 0.5 e a perda cai. Com taxa um, o vetor é [1,2], previsão cinco e perda cresce. Esse caso inclui intercepto e inclinação; ele difere do exemplo da leitura, em que apenas a inclinação podia variar. Identificar essa diferença evita comparar resultados de problemas distintos.
O código também mantém a conta unidimensional da leitura para demonstrar perdas 0.5, 0.18 e 4.5. Se sua execução devolver outros números, confira primeiro quais parâmetros estão livres. Em seguida mude temporariamente a atualização para recalcular a derivada de m após alterar b. Você estará executando outro procedimento, e a igualdade com step simultâneo deixará de valer. Não há necessidade de chamar todo procedimento sequencial de incorreto; o erro é afirmar que implementou a fórmula simultânea enquanto executa uma atualização diferente.
Treinar, comparar e registrar o que foi provado
FundamentosExecute mil e quinhentos passos com taxa 0.1 sobre os três registros. Em cada iteração, compare a nova perda com a anterior e registre alguns pontos da trajetória. O programa deve aproximar intercepto 7/6, inclinação 0.5 e perda 1/36. Essa referência vem da resolução algébrica anterior, oferecendo uma segunda rota para conferir o ajuste. Um teste de monotonicidade é adequado a esta quadrática com a taxa escolhida; não deve ser copiado como requisito universal para treinamento estocástico, no qual lotes diferentes podem produzir oscilações.
No relatório, apresente objetivo, derivadas, tolerância, histórico e diagnósticos negativos. Dê um ponto de evidência a cada um desses cinco elementos; o resultado final sozinho não substitui os anteriores. Inclua uma limitação: o caso é pequeno, convexo e sem separação de avaliação, portanto prova apenas que nossa rotina ajusta esta função. Retome a probabilidade: ter poucos registros torna uma conclusão operacional incerta, mesmo que a otimização seja exata. Na unidade seguinte, a divisão dos dados tratará a diferença entre aprender a amostra e avaliar novos exemplos.
import assert from 'node:assert/strict';
const data=[{x:0,y:1},{x:1,y:2},{x:2,y:2}];
function validate(theta,rows){
if(theta.length!==2||!theta.every(Number.isFinite))throw Error('parâmetros inválidos');
if(!rows.length||!rows.every(r=>Number.isFinite(r.x)&&Number.isFinite(r.y)))throw Error('dados inválidos');
}
function loss(theta,rows){
validate(theta,rows);
return rows.reduce((sum,{x,y})=>sum+0.5*(theta[0]+theta[1]*x-y)**2,0)/rows.length;
}
function gradient(theta,rows){
validate(theta,rows);
const g=[0,0];
for(const {x,y} of rows){
const residual=theta[0]+theta[1]*x-y;
g[0]+=residual/rows.length;g[1]+=residual*x/rows.length;
}
return g;
}
function numerical(theta,rows,h=1e-5){
return theta.map((_,i)=>{
const plus=[...theta],minus=[...theta];plus[i]+=h;minus[i]-=h;
return (loss(plus,rows)-loss(minus,rows))/(2*h);
});
}
function step(theta,rows,rate){
if(!Number.isFinite(rate)||rate<=0)throw Error('taxa inválida');
const g=gradient(theta,rows);
return theta.map((value,i)=>value-rate*g[i]); // Atualização simultânea.
}
const near=(a,b,tolerance=1e-7)=>assert.ok(Math.abs(a-b)<tolerance,String(a)+' != '+b);
const point=[0.3,-0.2],analytic=gradient(point,data),numeric=numerical(point,data);
analytic.forEach((g,i)=>near(g,numeric[i]));
const duplicated=[...data,...data];
near(loss(point,data),loss(point,duplicated));
gradient(point,duplicated).forEach((g,i)=>near(g,analytic[i]));
const one=[{x:2,y:1}],start=[0,0];
const small=step(start,one,0.1),large=step(start,one,1);
assert.ok(loss(small,one)<loss(start,one));
assert.ok(loss(large,one)>loss(start,one));
const onlySlope=w=>0.5*(2*w-1)**2;
near(onlySlope(0),0.5);near(onlySlope(0.2),0.18);near(onlySlope(2),4.5);
let fitted=[0,0];const history=[];
for(let i=0;i<1500;i++){
const next=step(fitted,data,0.1);
assert.ok(loss(next,data)<=loss(fitted,data)+1e-12);
fitted=next;if(i%300===0)history.push(loss(fitted,data));
}
near(fitted[0],7/6,1e-6);near(fitted[1],0.5,1e-6);
near(loss(fitted,data),1/36,1e-9);
assert.throws(()=>step(start,data,0),/taxa/);
assert.throws(()=>loss([NaN,0],data),/parâmetros/);
assert.throws(()=>loss(start,[]),/dados/);
console.log({analytic,numeric,small,large,fitted,history});Exercício aplicado
Construa uma rotina de otimização cuja evidência permita localizar erros de fórmula e de procedimento.
- Implemente loss e gradient com média consistente e validação.
- Compare derivadas por diferença central em ponto fora do mínimo.
- Demonstre invariância da média ao duplicar o lote.
- Compare passos pequeno e grande e mantenha atualização simultânea.
- Treine a reta e confira parâmetros, perda e casos inválidos.
Abrir resolução comentada
A implementação completa preserva a ordem [b,m], valida cada registro e usa erro definido como previsão menos observado. A diferença central opera sobre cópias e verifica cada componente fora da solução. Duplicar o lote não muda a função média, o que é testado tanto na perda quanto no gradiente. Os erros de entrada têm asserções próprias, com mensagens correspondentes ao contrato violado.
Os dois testes de passo separam a direção de queda do tamanho do deslocamento. O caso de dois parâmetros confirma melhora com taxa 0.1 e piora com taxa um. A conta de um parâmetro retoma os valores da leitura. A função step calcula o gradiente antes de qualquer alteração, portanto implementa a atualização simultânea declarada. A trajetória final é comparada à resposta algébrica e à escala correta de perda, sem misturar SSE com média.
A resolução exige ainda um relatório de diagnóstico: retirar x deve quebrar a comparação numérica; retirar a divisão por n deve quebrar a invariância da duplicação; escolher passo excessivo deve piorar a perda do caso local. Descreva essas experiências separadamente. Elas ajudam a identificar a causa de uma falha, mas não demonstram que a mesma taxa será adequada a redes, dados com outras escalas ou superfícies não convexas.
import assert from 'node:assert/strict';
const data=[{x:0,y:1},{x:1,y:2},{x:2,y:2}];
function validate(theta,rows){
if(theta.length!==2||!theta.every(Number.isFinite))throw Error('parâmetros inválidos');
if(!rows.length||!rows.every(r=>Number.isFinite(r.x)&&Number.isFinite(r.y)))throw Error('dados inválidos');
}
function loss(theta,rows){
validate(theta,rows);
return rows.reduce((sum,{x,y})=>sum+0.5*(theta[0]+theta[1]*x-y)**2,0)/rows.length;
}
function gradient(theta,rows){
validate(theta,rows);
const g=[0,0];
for(const {x,y} of rows){
const residual=theta[0]+theta[1]*x-y;
g[0]+=residual/rows.length;g[1]+=residual*x/rows.length;
}
return g;
}
function numerical(theta,rows,h=1e-5){
return theta.map((_,i)=>{
const plus=[...theta],minus=[...theta];plus[i]+=h;minus[i]-=h;
return (loss(plus,rows)-loss(minus,rows))/(2*h);
});
}
function step(theta,rows,rate){
if(!Number.isFinite(rate)||rate<=0)throw Error('taxa inválida');
const g=gradient(theta,rows);
return theta.map((value,i)=>value-rate*g[i]); // Atualização simultânea.
}
const near=(a,b,tolerance=1e-7)=>assert.ok(Math.abs(a-b)<tolerance,String(a)+' != '+b);
const point=[0.3,-0.2],analytic=gradient(point,data),numeric=numerical(point,data);
analytic.forEach((g,i)=>near(g,numeric[i]));
const duplicated=[...data,...data];
near(loss(point,data),loss(point,duplicated));
gradient(point,duplicated).forEach((g,i)=>near(g,analytic[i]));
const one=[{x:2,y:1}],start=[0,0];
const small=step(start,one,0.1),large=step(start,one,1);
assert.ok(loss(small,one)<loss(start,one));
assert.ok(loss(large,one)>loss(start,one));
const onlySlope=w=>0.5*(2*w-1)**2;
near(onlySlope(0),0.5);near(onlySlope(0.2),0.18);near(onlySlope(2),4.5);
let fitted=[0,0];const history=[];
for(let i=0;i<1500;i++){
const next=step(fitted,data,0.1);
assert.ok(loss(next,data)<=loss(fitted,data)+1e-12);
fitted=next;if(i%300===0)history.push(loss(fitted,data));
}
near(fitted[0],7/6,1e-6);near(fitted[1],0.5,1e-6);
near(loss(fitted,data),1/36,1e-9);
assert.throws(()=>step(start,data,0),/taxa/);
assert.throws(()=>loss([NaN,0],data),/parâmetros/);
assert.throws(()=>loss(start,[]),/dados/);
console.log({analytic,numeric,small,large,fitted,history});Como conferir seu resultado
- Gradiente analítico e numérico coincidem por componente.
- Duplicação preserva média e gradiente.
- Passo excessivo piora o caso local.
- Atualização usa o mesmo estado para os dois parâmetros.
- Treinamento aproxima [7/6,0.5] e 1/36.
- Taxa inválida, NaN e lote vazio são rejeitados.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Por que copiamos theta na diferença central?
Para variar apenas uma coordenada sem contaminar os outros testes.
Cada derivada parcial exige manter as demais coordenadas fixas.
2. Por que testar apenas no mínimo é fraco?
Um erro de fórmula pode também devolver zero ali.
Um ponto fora do mínimo exercita contribuições não nulas.
3. A perda deve sempre cair em todo treinamento de rede?
Não.
A propriedade testada vale para nosso caso e taxa; lotes estocásticos e superfícies diferentes mudam o comportamento.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- 18.02SC Multivariable Calculus — syllabus
MIT OpenCourseWare • consulta: 2026-10-06
FundamentosDerivadas parciais, gradientes, regra da cadeia e otimização; estudo com problemas antes da solução.
Limites: A unidade oferece preparação inicial com polinômios; não substitui cálculo de uma e várias variáveis.
- 18.06 Linear Algebra — syllabus
MIT OpenCourseWare • consulta: 2026-10-06
MatemáticaVetores, sistemas lineares, projeções e mínimos quadrados como fundamentos da disciplina.
Limites: Programa da disciplina de 2010; exemplos numéricos e implementação desta preparação são originais e não cobrem o curso completo.