LABORATÓRIO · SVM LINEAR

Treine a margem, não apenas a classificação.

Duas características descrevem cada amostra. Observe a reta u=0, os limites u=−1 e u=+1 e os pontos que ainda geram perda hinge.

u = w₁x₁ + w₂x₂ + bm = y × uL = máx(0, 1 − m)m ≤ 1 → ajustar
ÉPOCAS0
ACURÁCIA50%
PERDA MÉDIA1,000
LARGURA DA MARGEM
VETORES DE SUPORTE10

Plano de decisão

Os círculos e quadrados verdes estão sobre a margem ou dentro dela.

Modelo inicial
classe −1classe +1vetor de suporteu=0u=±1

Matemática da última amostra

Os valores anteriores são usados para calcular a correção mostrada.

Comece o treinamento

Clique em “Treinar próxima amostra” para acompanhar uma atualização completa.

Perda × resposta

A perda hinge deve cair enquanto a acurácia se aproxima de 100%.

perda hingeacurácia

Estado de todas as amostras

A linha verde indica margem funcional m≤1,05. A pequena tolerância visual mantém destacados os pontos praticamente sobre u=±1.

CÓDIGO COMPLETO E EXECUTÁVEL

Treine, avalie e use uma SVM linear

O programa contém dados de treino e teste, otimização da perda hinge, parada antecipada, avaliação e previsão de uma nova entrada.

potencial()treinarAmostra()treinar()avaliar()prever()
svm-linear-completa.jsexecute do início ao fim
// Cada amostra contém [x1, x2, y].
// As classes da SVM binária são -1 e +1.
var dados = [
  [-3.0, -1.0, -1],
  [-2.0,  1.0, -1],
  [ 1.0, -0.4, +1],
  [ 2.5,  0.8, +1]
];

var teste = [
  [-2.5,  0.2, -1],
  [-1.5, -0.8, -1],
  [ 1.5,  0.1, +1],
  [ 3.0,  1.2, +1]
];

var pesos = [0, 0];
var bias = 0;

// Calcula u = w1*x1 + w2*x2 + b.
function potencial(amostra) {
  return pesos[0] * amostra[0]
       + pesos[1] * amostra[1]
       + bias;
}

// O sinal de u determina a classe prevista.
function prever(amostra) {
  if (potencial(amostra) >= 0) {
    return +1;
  }
  return -1;
}

// Calcula L = max(0, 1 - y*u).
function perdaHinge(amostra) {
  var margem = amostra[2] * potencial(amostra);
  return Math.max(0, 1 - margem);
}

// Faz uma atualização pela margem suave.
function treinarAmostra(amostra, taxa, C, lambda) {
  var x1 = amostra[0];
  var x2 = amostra[1];
  var y = amostra[2];
  var margem = y * potencial(amostra);

  // A regularização reduz um pouco os pesos.
  pesos[0] = (1 - taxa * lambda) * pesos[0];
  pesos[1] = (1 - taxa * lambda) * pesos[1];

  // Se m < 1, a amostra viola a margem e corrige o modelo.
  if (margem < 1) {
    pesos[0] = pesos[0] + taxa * C * y * x1;
    pesos[1] = pesos[1] + taxa * C * y * x2;
    bias = bias + taxa * C * y;
  }
}

// Uma época apresenta todas as amostras uma vez.
function treinarEpoca(taxa, C, lambda) {
  for (var i = 0; i < dados.length; i++) {
    treinarAmostra(dados[i], taxa, C, lambda);
  }
}

// Repete épocas e interrompe quando a perda praticamente não muda.
function treinar(maximoEpocas, taxa, C, lambda) {
  var perdaAnterior = Infinity;

  for (var epoca = 1; epoca <= maximoEpocas; epoca++) {
    treinarEpoca(taxa, C, lambda);

    var perdaAtual = 0;
    for (var i = 0; i < dados.length; i++) {
      perdaAtual = perdaAtual + perdaHinge(dados[i]);
    }
    perdaAtual = perdaAtual / dados.length;

    if (Math.abs(perdaAnterior - perdaAtual) < 0.0001) return epoca;
    perdaAnterior = perdaAtual;
  }
  return maximoEpocas;
}

function avaliar(amostras) {
  var acertos = 0;
  for (var i = 0; i < amostras.length; i++) {
    if (prever(amostras[i]) === amostras[i][2]) acertos++;
  }
  return acertos / amostras.length;
}

// ----------------------- USO DO MODELO -----------------------
var epocasUsadas = treinar(500, 0.02, 1, 0.01);
console.log('Épocas:', epocasUsadas);
console.log('Pesos e bias:', pesos, bias);
console.log('Acurácia de teste:', avaliar(teste));
console.log('Previsão para [2, 0.5]:', prever([2, 0.5]));