• ലക്ഷ്യം
  • പ്രതീക്ഷ പരമാവധികരണം (Expectation Maximization)
  • ഇന്ററാക്ടീവ് ഡെമോ
  • ഹോം
  • പോസ്റ്റുകൾ
  • കുറിപ്പുകൾ
  • പുസ്തകശാല
  • രചയിതാവ്
🇺🇸 en 🇫🇷 fr 🇨🇳 zh

Nathaniel Thomas

ഇന്ററാക്ടീവ് ഗൗസിയൻ മിശ്രണ മോഡലുകൾ

2024, ഡിസംബർ 6

ലക്ഷ്യം

നമുക്ക് ഫീച്ചറുകളുടെ ഒരു ഡാറ്റാസെറ്റ് ഉണ്ടെന്ന് കരുതുക, പക്ഷേ ലേബലുകളൊന്നുമില്ല. ഡാറ്റാസെറ്റിൽ K ക്ലാസുകൾ ഉണ്ടെന്ന് നമുക്ക് അറിയാമെങ്കിൽ (അല്ലെങ്കിൽ ഊഹിക്കാമെങ്കിൽ), ഡാറ്റാസെറ്റിനെ K ക്ലാസ്–കണ്ടീഷണൽ ഗൗസിയനുകളുടെ ഭാരം കണക്കാക്കിയ ശരാശരിയായി മാതൃകയാക്കാം. ഇതാണ് ഗൗസിയൻ മിശ്രിത മാതൃകകൾ (Gaussian Mixture Models) ചെയ്യുന്നത്.

മാതൃക θ={πk​,μk​,σk2​}k=1K​ എന്ന പാരാമീറ്ററുകളാൽ നിർവചിക്കപ്പെട്ടതാണെന്ന് നമ്മൾ അനുമാനിക്കുന്നു, ഇവിടെ πk​ മാതൃകയിലെ kth ഗൗസിയന്റെ ഭാരം നിർണ്ണയിക്കുന്നു.

നമ്മുടെ ഡാറ്റാസെറ്റ് D={xi​}i=1N​ i.i.d. ആയതിനാൽ, അതിന്റെ ലോഗ്–സാധ്യത (log-likelihood)

L(θ)​=i=1∑N​log(p(xi​))=i=1∑N​log(k=1∑K​N(xi​∣μk​,σk2​)πk​)​

പ്രതീക്ഷ പരമാവധികരണം (Expectation Maximization)

ഞങ്ങളുടെ ഡാറ്റയുടെ സാധ്യത പരമാവധികരിക്കുന്ന μk​,σk2​ കണ്ടെത്താൻ, ഞങ്ങൾ ഇനിപ്പറയുന്ന പ്രക്രിയ ഉപയോഗിക്കും:

  1. θ={πk​,μk​,σk2​}k=1K​ എന്നതിന് പ്രാഥമിക ഊഹങ്ങൾ കണക്കാക്കുക

  2. xi​ ക്ലാസ് k ലേക്ക് ചേരുന്നതിന്റെ സാധ്യത കണക്കാക്കുക. ഇത് rik​ അല്ലെങ്കിൽ xi​ ന്റെ k ലേക്കുള്ള ഉത്തരവാദിത്വം എന്ന് സൂചിപ്പിക്കുന്നു

rik​=∑j=1K​πj​⋅N(xi​∣μj​,σj2​)πk​⋅N(xi​∣μk​,σk2​)​
  1. ഞങ്ങൾ അപ്ഡേറ്റ് ചെയ്യുന്നു
    • ഭാരങ്ങൾ πk​ എന്നത് ഗാസിയൻ k ലേക്കുള്ള ശരാശരി ഉത്തരവാദിത്വമാണ്
    • മീൻസ് μk​ എന്നത് ഡാറ്റാപോയിന്റുകളുടെ ശരാശരിയാണ്, rik​ ഉപയോഗിച്ച് എല്ലാ i ക്കും ഭാരം നൽകുന്നു
    • വേരിയൻസ് σk2​ എന്നത് പുതിയ μk​ ലേക്കുള്ള ഡാറ്റാപോയിന്റുകളുടെ വേരിയൻസ് ആണ്, അതുപോലെ rik​ ഉപയോഗിച്ച് ഭാരം നൽകുന്നു
πk​μk​σk2​​=N∑i=1N​rik​​=∑i=1N​rik​∑i=1N​rik​⋅xi​​=∑i=1N​rik​∑i=1N​rik​⋅(xi​−μk​)2​​

ഈ പ്രക്രിയയും കെർണൽ റിഗ്രഷൻ എന്നതിനും ഇടയിലുള്ള സാദൃശ്യം ശ്രദ്ധിക്കുക! ഈ സാഹചര്യത്തിൽ, കെർണൽ ഫംഗ്ഷൻ rik​ ആണ്, ഇത് xi​ ഫീച്ചറുകളുടെ ഒരു പരിസരത്തെ നിർവചിക്കുന്നു, അത് ക്ലാസ് k ലേക്ക് ചേരാനുള്ള സാധ്യതയുണ്ട്.

ഭാരങ്ങൾ കൺവേർജ് ആകുന്നതുവരെ ഘട്ടങ്ങൾ 2 ഉം 3 ഉം ആവർത്തിക്കുന്നു.

ഇന്ററാക്ടീവ് ഡെമോ

താഴെ EM അൽഗോരിതത്തിന്റെ ഒരു ഇന്ററാക്ടീവ് ഡെമോയുണ്ട്. ഡാറ്റ K ഗൗസിയനുകളിൽ നിന്ന് ഉത്പാദിപ്പിക്കപ്പെടുന്നു, അവയുടെ മീൻസ്, വേരിയൻസുകൾ, ഭാരങ്ങൾ എന്നിവ ക്രമരഹിതമായി തിരഞ്ഞെടുക്കുന്നു. തുടർന്ന്, K ഗൗസിയനുകളുടെ ഒരു GM മോഡൽ ഡാറ്റയിൽ ഫിറ്റ് ചെയ്യുന്നു.

നിങ്ങൾക്ക് Start ക്ലിക്ക് ചെയ്ത് ഇത് ആവർത്തിച്ച് പരീക്ഷിക്കാം. ഡെസ്ക്ടോപ്പ് ശുപാർശ ചെയ്യുന്നു.

Iteration: 0
$k$ True $(\mu_k, \sigma_k^2)$ Est $(\hat \mu_k, \hat \sigma_k^2)$ True $\pi_k$ Est $\hat{\pi}_k$
കോഡ്

ഇതാ ജാവാസ്ക്രിപ്റ്റിലെ കോർ അൽഗോരിതം കോഡ്. ഇത് നേരിട്ട് മുകളിലെ പ്ലോട്ട് പുനർനിർമ്മിക്കില്ല, കാരണം പ്ലോട്ടിംഗ് കോഡും HTML/CSS ഉം ഞാൻ ഒഴിവാക്കിയിട്ടുണ്ട്. മുഴുവൻ കാണാൻ Inspect Element ഉപയോഗിക്കാം.

function randn() {
  let u = 0, v = 0;
  while(u === 0) u = Math.random();
  while(v === 0) v = Math.random();
  return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
}

function gaussianPDF(x, mean, variance) {
  const std = Math.sqrt(variance);
  const coeff = 1.0 / (std * Math.sqrt(2 * Math.PI));
  const exponent = -0.5 * Math.pow((x - mean)/std, 2);
  return coeff * Math.exp(exponent);
}

function generateSeparatedMeans(C) {
  let candidate = [];
  for (let i = 0; i < C; i++) {
    candidate.push(Math.random());
  }
  candidate.sort((a,b) => a - b);
  let means = candidate.map(x => -5 + x*10);
  for (let i = 1; i < C; i++) {
    if (means[i] - means[i-1] < 0.5) {
      means[i] = means[i-1] + 0.5;
    }
  }
  return means;
}

function generateData(C, N=1000) {
  let means = generateSeparatedMeans(C);
  let variances = [];
  let weights = [];
  for (let i = 0; i < C; i++) {
    variances.push(0.5 + 1.5*Math.random());
    weights.push(1.0/C);
  }

  let data = [];
  for (let i = 0; i < N; i++) {
    const comp = Math.floor(Math.random() * C);
    const x = means[comp] + Math.sqrt(variances[comp])*randn();
    data.push(x);
  }
  return {data, means, variances, weights};
}

function decentInitialGuess(C, data) {
  const N = data.length;
  let means = [];
  let variances = [];
  let weights = [];
  for (let c = 0; c < C; c++) {
    means.push(data[Math.floor(Math.random()*N)]);
    variances.push(1.0);
    weights.push(1.0/C);
  }
  return {means, variances, weights};
}

function emGMM(data, C, maxIter=100, tol=1e-4) {
  const N = data.length;
  let init = decentInitialGuess(C, data);
  let means = init.means.slice();
  let variances = init.variances.slice();
  let weights = init.weights.slice();

  let logLikOld = -Infinity;
  let paramsHistory = [];

  for (let iter = 0; iter < maxIter; iter++) {
    let resp = new Array(N).fill(0).map(() => new Array(C).fill(0));
    for (let i = 0; i < N; i++) {
      let total = 0;
      for (let c = 0; c < C; c++) {
        const val = weights[c]*gaussianPDF(data[i], means[c], variances[c]);
        resp[i][c] = val;
        total += val;
      }
      for (let c = 0; c < C; c++) {
        resp[i][c] /= (total + 1e-15);
      }
    }

    for (let c = 0; c < C; c++) {
      let sumResp = 0;
      let sumMean = 0;
      let sumVar = 0;
      for (let i = 0; i < N; i++) {
        sumResp += resp[i][c];
        sumMean += resp[i][c]*data[i];
      }
      const newMean = sumMean / (sumResp + 1e-15);

      for (let i = 0; i < N; i++) {
        let diff = data[i] - newMean;
        sumVar += resp[i][c]*diff*diff;
      }
      const newVar = sumVar/(sumResp + 1e-15);

      means[c] = newMean;
      variances[c] = Math.max(newVar, 1e-6);
      weights[c] = sumResp/N;
    }

    let logLik = 0;
    for (let i = 0; i < N; i++) {
      let p = 0;
      for (let c = 0; c < C; c++) {
        p += weights[c]*gaussianPDF(data[i], means[c], variances[c]);
      }
      logLik += Math.log(p + 1e-15);
    }

    paramsHistory.push({
      means: means.slice(),
      variances: variances.slice(),
      weights: weights.slice()
    });

    if (Math.abs(logLik - logLikOld) < tol) {
      break;
    }
    logLikOld = logLik;
  }
  return paramsHistory;
}

←
ലോക്കൽ അപ്രോക്സിമേഷൻ
ആദ്യ തത്വങ്ങളിൽ നിന്നുള്ള എൻട്രോപ്പി
→

back to top