ലക്ഷ്യം
നമുക്ക് ഫീച്ചറുകളുടെ ഒരു ഡാറ്റാസെറ്റ് ഉണ്ടെന്ന് കരുതുക, പക്ഷേ ലേബലുകളൊന്നുമില്ല. ഡാറ്റാസെറ്റിൽ ക്ലാസുകൾ ഉണ്ടെന്ന് നമുക്ക് അറിയാമെങ്കിൽ (അല്ലെങ്കിൽ ഊഹിക്കാമെങ്കിൽ), ഡാറ്റാസെറ്റിനെ ക്ലാസ്–കണ്ടീഷണൽ ഗൗസിയനുകളുടെ ഭാരം കണക്കാക്കിയ ശരാശരിയായി മാതൃകയാക്കാം. ഇതാണ് ഗൗസിയൻ മിശ്രിത മാതൃകകൾ (Gaussian Mixture Models) ചെയ്യുന്നത്.
മാതൃക എന്ന പാരാമീറ്ററുകളാൽ നിർവചിക്കപ്പെട്ടതാണെന്ന് നമ്മൾ അനുമാനിക്കുന്നു, ഇവിടെ മാതൃകയിലെ th ഗൗസിയന്റെ ഭാരം നിർണ്ണയിക്കുന്നു.
നമ്മുടെ ഡാറ്റാസെറ്റ് i.i.d. ആയതിനാൽ, അതിന്റെ ലോഗ്–സാധ്യത (log-likelihood)
പ്രതീക്ഷ പരമാവധികരണം (Expectation Maximization)
ഞങ്ങളുടെ ഡാറ്റയുടെ സാധ്യത പരമാവധികരിക്കുന്ന കണ്ടെത്താൻ, ഞങ്ങൾ ഇനിപ്പറയുന്ന പ്രക്രിയ ഉപയോഗിക്കും:
-
എന്നതിന് പ്രാഥമിക ഊഹങ്ങൾ കണക്കാക്കുക
-
ക്ലാസ് ലേക്ക് ചേരുന്നതിന്റെ സാധ്യത കണക്കാക്കുക. ഇത് അല്ലെങ്കിൽ ന്റെ ലേക്കുള്ള ഉത്തരവാദിത്വം എന്ന് സൂചിപ്പിക്കുന്നു
- ഞങ്ങൾ അപ്ഡേറ്റ് ചെയ്യുന്നു
- ഭാരങ്ങൾ എന്നത് ഗാസിയൻ ലേക്കുള്ള ശരാശരി ഉത്തരവാദിത്വമാണ്
- മീൻസ് എന്നത് ഡാറ്റാപോയിന്റുകളുടെ ശരാശരിയാണ്, ഉപയോഗിച്ച് എല്ലാ ക്കും ഭാരം നൽകുന്നു
- വേരിയൻസ് എന്നത് പുതിയ ലേക്കുള്ള ഡാറ്റാപോയിന്റുകളുടെ വേരിയൻസ് ആണ്, അതുപോലെ ഉപയോഗിച്ച് ഭാരം നൽകുന്നു
ഈ പ്രക്രിയയും കെർണൽ റിഗ്രഷൻ എന്നതിനും ഇടയിലുള്ള സാദൃശ്യം ശ്രദ്ധിക്കുക! ഈ സാഹചര്യത്തിൽ, കെർണൽ ഫംഗ്ഷൻ ആണ്, ഇത് ഫീച്ചറുകളുടെ ഒരു പരിസരത്തെ നിർവചിക്കുന്നു, അത് ക്ലാസ് ലേക്ക് ചേരാനുള്ള സാധ്യതയുണ്ട്.
ഭാരങ്ങൾ കൺവേർജ് ആകുന്നതുവരെ ഘട്ടങ്ങൾ 2 ഉം 3 ഉം ആവർത്തിക്കുന്നു.
ഇന്ററാക്ടീവ് ഡെമോ
താഴെ EM അൽഗോരിതത്തിന്റെ ഒരു ഇന്ററാക്ടീവ് ഡെമോയുണ്ട്. ഡാറ്റ ഗൗസിയനുകളിൽ നിന്ന് ഉത്പാദിപ്പിക്കപ്പെടുന്നു, അവയുടെ മീൻസ്, വേരിയൻസുകൾ, ഭാരങ്ങൾ എന്നിവ ക്രമരഹിതമായി തിരഞ്ഞെടുക്കുന്നു. തുടർന്ന്, ഗൗസിയനുകളുടെ ഒരു GM മോഡൽ ഡാറ്റയിൽ ഫിറ്റ് ചെയ്യുന്നു.
നിങ്ങൾക്ക് Start
ക്ലിക്ക് ചെയ്ത് ഇത് ആവർത്തിച്ച് പരീക്ഷിക്കാം. ഡെസ്ക്ടോപ്പ് ശുപാർശ ചെയ്യുന്നു.
$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;
}