Try drawing a digit on the canvas!
1v1 Least Squares (n/a ms)
ഈ ലേഖനത്തിൽ, MNIST ഡാറ്റാസെറ്റ് പ്രതിരോധിക്കുന്ന 3 അടിസ്ഥാന മോഡലുകൾ ഞങ്ങൾ പരിശോധിക്കുന്നു, അവയുടെ സവിശേഷതകൾ, ശക്തികൾ, ദുർബലതകൾ താരതമ്യം ചെയ്യുന്നു. മുകളിലെ ബാർ ഗ്രാഫുകളിൽ ഓരോ മോഡലിന്റെയും ഔട്ട്പുട്ട് കാണാനും അവയുമായി ഇന്ററാക്ടീവായി പ്ലേ ചെയ്യാനും നിങ്ങൾക്ക് കഴിയും.
ടാസ്ക്
മെഷീൻ ലേണിംഗിനൊപ്പം പരിചയമില്ലാത്തവർക്ക്, ഒരു ഇമേജിനെ ഒരു സംഖ്യയാക്കി മാറ്റുന്നത് ഒരു ബുദ്ധിമുട്ടുള്ള ടാസ്ക് ആയി തോന്നിയേക്കാം. എന്നാൽ, നമ്മൾ ഈ പ്രശ്നത്തെ ഇനിപ്പറയുന്ന രീതിയിൽ ചിന്തിച്ചാൽ ഇത് എളുപ്പമാകും:
ഒരു ഗ്രേസ്കെയിൽ ചിത്രം എന്നത് പിക്സൽ ബ്രൈറ്റ്നെസുകളുടെ ഒരു ഗ്രിഡ് മാത്രമാണ്, അത് യഥാർത്ഥ മൂല്യങ്ങളാണ്. അതായത്, ഓരോ ചിത്രവും എന്ന സെറ്റിലെ ഒരു ഘടകമാണ്, ഇവിടെ എന്നിവ യഥാക്രമം ചിത്രത്തിന്റെ വീതിയും ഉയരവുമാണ്. അതിനാൽ, നമുക്ക് എന്ന ഫംഗ്ഷൻ കണ്ടെത്താൻ കഴിയുമെങ്കിൽ, ഈ പ്രശ്നം പരിഹരിക്കാനാകും.
ഇത് ചെയ്യുന്നതിന്, ഞങ്ങൾ ഞങ്ങളുടെ ട്രെയിനിംഗ് ഇമേജുകൾ ലേബലുകൾ ഉപയോഗിച്ച് ഒരു മോഡൽ നിർമ്മിക്കുന്നു.
ലീസ്റ്റ് സ്ക്വയേഴ്സ്
ഈ രീതിയിൽ, 0..9 വരെയുള്ള നമ്മുടെ വിഭാഗങ്ങളിൽ നിന്ന് തിരഞ്ഞെടുത്ത ഓരോ അദ്വിതീയ ജോഡി -യ്ക്കും വരെ 45 ലീനിയർ മാപ്പുകൾ സൃഷ്ടിക്കുന്നു, ഇത് ഒരു ഇമേജ് ജോഡി അല്ലെങ്കിൽ -യിൽ പെടുന്നുവെന്ന് അനുമാനിക്കുന്നു. ലീനിയർ ആൾജിബ്ര ഉപയോഗിച്ച് മീൻ സ്ക്വയേഡ് എറർ (MSE) കുറയ്ക്കാം. ആദ്യം, -ലെ ഇമേജുകൾ കൈകാര്യം ചെയ്യുന്നതിന് പകരം, അവയെ -ലേക്ക് “ഫ്ലാറ്റൻ” ചെയ്യാം.
-യുടെ ഭാരങ്ങളെ എന്ന് നിർവചിക്കാം, ഇത് നീളമുള്ള ഒരു വെക്ടർ ആണ്. മോഡലിന്റെ ഔട്ട്പുട്ട് ലഭിക്കാൻ, ഞങ്ങൾ കണക്കാക്കുന്നു
ഇവിടെ ഒരു അക്കമാണ്.
എല്ലാ സാമ്പിളുകളിലും MSE കുറയ്ക്കാൻ ഞങ്ങൾ ആഗ്രഹിക്കുന്നു
ഇത് ചെയ്യുന്നതിന്, ഞങ്ങൾ ഒരു പുതിയ മാട്രിക്സ് സൃഷ്ടിക്കുന്നു, ഇതിൽ ക്ലാസ് അല്ലെങ്കിൽ -യിൽ പെടുന്ന ഇമേജുകൾ മാത്രമേ ഉള്ളൂ, ബയസിനായി ന്റെ ഒരു കോളം ഉൾപ്പെടുന്നു, ഒപ്പം എന്ന മാട്രിക്സും, ഇതിൽ -ലെ ലേബലുകൾ മാത്രമേ ഉള്ളൂ, പക്ഷേ എന്നത് ഉം എന്നത് ഉം ആയി മാറ്റുന്നു.
ഇപ്പോൾ, ഞങ്ങളുടെ പ്രശ്നം ഇതിലേക്ക് ചുരുങ്ങിയിരിക്കുന്നു
ഇതിന്റെ പരിഹാരം ആണ്, ഇവിടെ എന്നത് മാട്രിക്സ് -ന്റെ പ്സ്യൂഡോഇൻവേഴ്സ് ആണ് (പ്രൂഫ് വായനക്കാരന് വ്യായാമമായി വിട്ടുകൊടുക്കുന്നു 😁).
എല്ലാ ജോഡികൾക്കും (മൊത്തം 45) ലഭിച്ചാൽ, ഞങ്ങളുടെ ആവശ്യമായ ഫംഗ്ഷൻ ഇങ്ങനെ പ്രതിനിധീകരിക്കാം
def f(x):
score = [0] * 10
for i, j, f_ij in pair_functions:
out_ij = f_ij(x)
if out_ij > 0:
score[i] += 1
score[j] -= 1
else:
score[j] += 1
score[i] -= 1
return argmax(score)
45 മോഡലുകളിൽ ഓരോന്നും അതിന്റെ
അല്ലെങ്കിൽ
-യ്ക്ക് “വോട്ട്” ചെയ്യുന്നു. score
അറേ ആണ് മുകളിലെ ബാർ ഗ്രാഫിൽ നിങ്ങൾ കാണുന്നത്.
പൂർണ്ണമായും ബന്ധിപ്പിച്ച നെറ്റ്വർക്ക്
ഒരു പൂർണ്ണമായും ബന്ധിപ്പിച്ച നെറ്റ്വർക്ക് (Fully Connected Network), അല്ലെങ്കിൽ FCN, ഏറ്റവും കുറഞ്ഞ സ്ക്വയറുകളുടെ മോഡലിനേക്കാൾ വളരെ വലിയ ഒരു മോഡലാണ്. ഡാറ്റയുടെ പ്രധാന സബ്സ്പെയ്സിലേക്ക് ലേബലുകൾ പ്രൊജക്റ്റ് ചെയ്യുന്നതിന് പകരം, ഇൻപുട്ട് സ്പെയ്സിൽ നിന്ന് ഔട്ട്പുട്ട് സ്പെയ്സിലേക്ക് നേരിട്ട് ഒരു മാപ്പിംഗ് പഠിക്കാൻ നമുക്ക് കഴിയും.
ഒരു ലെയർ നെറ്റ്വർക്കിന്, ഇനിപ്പറയുന്ന രീതിയിൽ ഏകദേശം കണക്കാക്കാമെന്ന് നമ്മൾ അനുമാനിക്കുന്നു:
ഇവിടെ എന്നത് ചില നോൺലീനിയർ ഫംഗ്ഷനാണ്. ഗ്രേഡിയന്റ് ഡിസെന്റ് വഴി പ്രാദേശിക പരിസരത്ത് പിശക് (Categorical Cross Entropy) കുറയ്ക്കുന്ന രീതിയിൽ മാട്രിക്സ് പഠിക്കാൻ സാധ്യമാണ്. ഡെമോയിൽ, ഞങ്ങൾ ഒരു 2 ലെയർ നെറ്റ്വർക്ക് ഉപയോഗിക്കുന്നു, അത് ഇമേജ് ലേക്ക് മാപ്പ് ചെയ്യുന്നു, അതിന്റെ ഫലം ലേക്ക് മാപ്പ് ചെയ്യുന്നു. ഇത് ഇനിപ്പറയുന്ന രീതിയിൽ പ്രതിനിധീകരിക്കപ്പെടുന്നു:
ഇവിടെ നമ്മൾ മാട്രിക്സുകൾ ഉം ഉം പഠിക്കേണ്ടതുണ്ട്. ഞങ്ങളുടെ കാര്യത്തിൽ, എന്നും
എന്നും ലെ ഔട്ട്പുട്ട് ഒരു പ്രോബബിലിറ്റി ഡിസ്ട്രിബ്യൂഷനാക്കി മാറ്റുന്നു, ഇത് മുകളിലെ ബാർ ഗ്രാഫുകളിൽ കാണിച്ചിരിക്കുന്നു.
കൺവല്യൂഷണൽ നെറ്റ്വർക്ക്
മുകളിൽ പറഞ്ഞ രണ്ട് മോഡലുകളുടെ ഒരു പരിമിതി എന്നത് അവ മനുഷ്യർ പോലെ ദൃശ്യ സവിശേഷതകൾ കാണുന്നില്ല എന്നതാണ്. ഉദാഹരണത്തിന്, ഒരു കൈയെഴുത്ത് 1
എന്നത് ക്യാൻവാസിൽ എവിടെ വരച്ചാലും ഒരു
ആണ്. എന്നിരുന്നാലും, LS, FCN മോഡലുകൾക്ക് സ്ഥലം അല്ലെങ്കിൽ സമീപത എന്ന ആശയം ഇല്ലാത്തതിനാൽ, അവ ആ പിക്സലുകൾ കൃത്യമായി ഉള്ള വിഭാഗത്തെ സൂചിപ്പിക്കും.
ഇവിടെ, നാം കൺവല്യൂഷനുകൾ ഉപയോഗിക്കുന്നു. കൺവല്യൂഷനുകൾ ഒരു ഇമേജും ഒരു കെർണലും എടുത്ത്, ആ കെർണൽ ഇമേജിലൂടെ ഓടിക്കുകയും ഇമേജ് പിക്സലുകളുടെയും കെർണൽ മൂല്യങ്ങളുടെയും ഭാരം കൂടിയ തുക അടങ്ങിയ ഒരു ഔട്ട്പുട്ട് ഇമേജ് ഉണ്ടാക്കുകയും ചെയ്യുന്നു.
കൺവല്യൂഷനുകൾ സ്ഥലിക ഡാറ്റ എങ്ങനെ എൻകോഡ് ചെയ്യുന്നുവെന്ന് ശ്രദ്ധിക്കുക, സാധാരണ നെറ്റ്വർക്കുകൾ ചെയ്യാത്തതുപോലെ. സമീപത്തുള്ള പിക്സലുകൾ സാധാരണയായി പരസ്പരം ഉയർന്ന തോതിൽ ബന്ധപ്പെട്ടിരിക്കുന്നതിനാൽ, നമുക്ക് മാക്സ് പൂൾ ഉപയോഗിച്ച് കൺവല്യൂഷൻ ഔട്ട്പുട്ട് ഡൗൺസാമ്പിൾ ചെയ്യാനും മിക്കവാറും എല്ലാ വിവരങ്ങളും സംരക്ഷിക്കാനും കഴിയും. ഇമേജ് ഒരു കൂട്ടം (പരിശീലിപ്പിച്ച) കെർണലുകളിലൂടെ കടന്നുപോയ ശേഷം, നാം ഒരു പഠിച്ച സ്ഥലിക സവിശേഷതയുടെ അസ്തിത്വം പ്രതിനിധീകരിക്കുന്ന മാട്രിക്സുകളുടെ ഒരു സെറ്റ് ലഭിക്കുന്നു. ഒടുവിൽ, നമുക്ക് ഇവ ഫ്ലാറ്റൻ ചെയ്ത് ഒരു FCN-ലേക്ക് കടത്തിവിടാം, ഇതിന് ഇപ്പോൾ സ്ഥലിക ഡാറ്റയെ വിഭാഗങ്ങളിലേക്ക് മാപ്പ് ചെയ്യാനാകും.
ഈ FCN-ന്റെ (സോഫ്റ്റ്മാക്സ് ആക്റ്റിവേഷൻ ഉള്ള) ഔട്ട്പുട്ട് മുകളിൽ കാണിച്ചിരിക്കുന്നു.
മോഡൽ താരതമ്യം
കുറിപ്പ്: അവസാനത്തെ 3 കോളങ്ങൾ ഗുണാത്മകവും പരസ്പരം ആപേക്ഷികവുമാണ്.
മോഡൽ | പാരാമീറ്ററുകളുടെ എണ്ണം | പരിശീലന സമയം | അനുമാന സമയം | കൃത്യത |
---|---|---|---|---|
ലീസ്റ്റ് സ്ക്വയേഴ്സ് | കുറഞ്ഞ | വേഗത | കുറഞ്ഞ | |
എഫ്സിഎൻ | ഉയർന്ന | വേഗത | നല്ലത് | |
കൺവല്യൂഷണൽ നെറ്റ്വർക്ക് | വളരെ ഉയർന്ന | മന്ദഗതി | മികച്ചത് |
നിരീക്ഷണങ്ങൾ:
- ലീസ്റ്റ് സ്ക്വയേഴ്സ് മോഡൽ വളരെ വേഗതയുള്ളതാണ്, പക്ഷേ സാമാന്യവൽക്കരിക്കാനുള്ള കഴിവ് ദുർബലമാണ്
- സിഎൻഎൻ-ന്റെ പാരാമീറ്ററുകൾ സംഭരിക്കാൻ വളരെ കാര്യക്ഷമമാണ്
- സിഎൻഎൻ-ന്റെ അനുമാന സമയവുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ, ലീസ്റ്റ് സ്ക്വയേഴ്സും എഫ്സിഎനും വളരെ വേഗതയുള്ളവയാണ്
വ്യായാമങ്ങൾ
ഈ ഇൻപുട്ടുകളിലേക്ക് മോഡലുകൾ എങ്ങനെ പ്രതികരിക്കുന്നുവെന്ന് നോക്കുക:
- ശൂന്യമായ കാൻവാസ്
- മധ്യഭാഗത്ത് ഒരു
1
- ഇടത് വശത്ത് ഒരു
1
- വലത് വശത്ത് ഒരു
1
- മധ്യഭാഗത്ത് ഒരു വര/ഡോട്ട് ഉള്ള ഒരു
0
- മുകളിൽ അല്പം വിച്ഛേദിച്ച ഒരു
9
- അല്പം ചരിഞ്ഞ അക്കങ്ങൾ
- വളരെ നേർത്ത അക്കങ്ങൾ
- വളരെ കട്ടിയുള്ള അക്കങ്ങൾ
1 പിക്സൽ വ്യത്യാസമുള്ള 2 ഇൻപുട്ടുകൾ കണ്ടെത്താനാകുമോ, അവ വ്യത്യസ്ത വിഭാഗങ്ങളിലേക്ക് മാപ്പ് ചെയ്യുന്നുണ്ടോ?
നടപ്പിലാക്കൽ വിശദാംശങ്ങൾ
മൂന്ന് മോഡലുകളും നിങ്ങളുടെ ബ്രൗസറിൽ പ്ലെയിൻ ജാവാസ്ക്രിപ്റ്റിൽ പ്രവർത്തിക്കുന്നു; ഒരു ഫ്രെയിംവർക്കോ പാക്കേജോ ഉപയോഗിച്ചിട്ടില്ല.
കാൻവാസ്
കാൻവാസ് ഒരു നമ്പർ അറേയാൽ പിന്തുണയ്ക്കപ്പെട്ടിരിക്കുന്നു, അതിൽ പ്രദർശിപ്പിക്കുന്ന ആൽഫ മൂല്യം അടങ്ങിയിരിക്കുന്നു. ഏതെങ്കിലും പിക്സൽ അപ്ഡേറ്റ് ചെയ്യുമ്പോഴെല്ലാം, മുഴുവൻ കാൻവാസും വീണ്ടും വരയ്ക്കുന്നു. മറ്റൊരു രസകരമായ വിശദാംശം ഞാൻ ഉപയോഗിച്ച തെളിച്ചം കുറയുന്ന ഫംഗ്ഷൻ ആണ്:
const plateau = 0.3;
// dist എന്നത് കേന്ദ്രത്തിൽ നിന്നുള്ള distance^2 ആണ്
const alpha = Math.min(1 - dist / r2 + plateau, 1);
pixels[yc * 28 + xc] = Math.max(pixels[yc * 28 + xc], alpha);
ഞാൻ ആദ്യം 1-dist/r2
എന്ന തെളിച്ചം കുറയുന്ന ഫംഗ്ഷൻ പരീക്ഷിച്ചു, പക്ഷേ അത് കേന്ദ്രം വളരെയധികം മങ്ങിച്ചു. അതിനാൽ ഞാൻ plateau
വേരിയബിൾ ചേർത്തു, അത് ഫംഗ്ഷനെ മുകളിലേക്ക് മാറ്റുന്നു, പക്ഷേ Math.min
ഉപയോഗിച്ച് അത് ക്ലാമ്പ് ചെയ്തു, അതുവഴി ആൽഫ 1-ൽ കൂടുതൽ ആകാതിരിക്കും. ഇത് ബ്രഷിന് കൂടുതൽ സ്വാഭാവിക രൂപം നൽകുന്നു.
ലീസ്റ്റ് സ്ക്വയേഴ്സ്
ഞാൻ ECE 174-ൽ പ്രൊഫസർ പിയ പാലിനൊപ്പം ചെയ്ത ഒരു പ്രോജക്റ്റിൽ നിന്നാണ് ഈ ഭാരങ്ങൾ (weights) ലഭിച്ചത്. ഇൻഫറൻസ് എന്നത് 45 ഡോട്ട് ഉൽപ്പന്നങ്ങളും സ്കോറിംഗും മാത്രമാണ്.
function evalLSModel(digit, weights) {
const scores = new Array(10).fill(0);
for (const pairConfig of weights) {
const [i, j, w] = pairConfig;
// വെക്ടർ ഡോട്ട് ഉൽപ്പന്നം
const result = vdot(digit, w);
if (result > 0) {
scores[i] += 1;
scores[j] -= 1;
} else {
scores[j] += 1;
scores[i] -= 1;
}
}
return scores;
}
പൂർണ്ണമായും ബന്ധിപ്പിച്ച നെറ്റ്വർക്ക്
FCN ഇൻഫറൻസിൽ പ്രധാനമായി ചെയ്യുന്നത് മാട്രിക്സ് ഡോട്ട് പ്രൊഡക്ട് ആണ്, ഇത് ഞാൻ സ്റ്റാൻഡേർഡ് രീതിയിൽ ഇംപ്ലിമെന്റ് ചെയ്തു.
function matrixDot(matrix1, matrix2, rows1, cols1, rows2, cols2) {
// മാട്രിക്സുകൾ ഗുണിക്കാൻ കഴിയുമോ എന്ന് പരിശോധിക്കുക
if (cols1 !== rows2) {
console.error("ഡസാധുവായ മാട്രിക്സ് അളവുകൾ ഡോട്ട് പ്രൊഡക്ടിന്");
return null;
}
// ഫലം മാട്രിക്സ് പൂജ്യങ്ങളുമായി ആരംഭിക്കുക
const result = new Array(rows1 * cols2).fill(0);
// ഡോട്ട് പ്രൊഡക്ട് നടത്തുക
for (let i = 0; i < rows1; i++) {
for (let j = 0; j < cols2; j++) {
for (let k = 0; k < cols1; k++) {
result[i * cols2 + j] +=
matrix1[i * cols1 + k] * matrix2[k * cols2 + j];
}
}
}
return result;
}
മെച്ചപ്പെട്ട കാഷെ ലൊക്കാലിറ്റിയും കുറഞ്ഞ ഹീപ്പ് അലോക്കേഷനുകളും ഉള്ളതിനാൽ മാട്രിക്സുകൾ ഒരൊറ്റ 1D Array
-ൽ സംഭരിച്ചു. മുകളിലെ ഫോർമുല പ്രകാരം, ഇൻഫറൻസിൽ 2 മാട്രിക്സ് ഡോട്ട് പ്രൊഡക്ടുകളും 2 ആക്റ്റിവേഷൻ ഫംഗ്ഷൻ ആപ്ലിക്കേഷനുകളും അടങ്ങിയിരിക്കുന്നു. push(1)
കോളുകൾ ബയസ് കണക്കാക്കാൻ ആണ്.
function evalNN(digit, weights) {
const digitCopy = [...digit];
digitCopy.push(1);
// ലെയർ 1 പാരാമീറ്ററുകൾ
const [w1, [rows1, cols1]] = weights[0];
const out1 = matrixDot(digitCopy, w1, 1, digitCopy.length, rows1, cols1).map(relu);
const [w2, [rows2, cols2]] = weights[1];
out1.push(1);
const out2 = matrixDot(out1, w2, 1, out1.length, rows2, cols2);
return softmax(out2);
}
കൺവല്യൂഷണൽ നെറ്റ്വർക്ക്
ഇവിടെയുള്ള കൺവല്യൂഷണൽ നെറ്റ്വർക്ക് വളരെ ചെറുതാണ്. പൈടോർച്ചിൽ ഇത് ഇങ്ങനെയാണ്:
nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(32, 64, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Dropout(0.5),
nn.Linear(1600, 10),
nn.Softmax(dim=1)
)
ഇൻഫറൻസിനായി, ഫോർവേഡ് പാസുകൾ ജാവാസ്ക്രിപ്റ്റിലേക്ക് പോർട്ട് ചെയ്യേണ്ടതുണ്ട്. Conv2d (ഇൻ/ഔട്ട് ചാനലുകൾ ഉപയോഗിച്ച്) ഇങ്ങനെ നൽകിയിരിക്കുന്നു:
function conv2d(
nInChan,
nOutChan,
inputData,
inputHeight,
inputWidth,
kernel,
bias,
) {
if (inputData.length !== inputHeight * inputWidth * nInChan) {
console.error("അസാധുവായ ഇൻപുട്ട് വലുപ്പം");
return;
}
if (kernel.length !== 3 * 3 * nInChan * nOutChan) {
console.error("അസാധുവായ കെർണൽ വലുപ്പം");
return;
}
const kernelHeight = 3;
const kernelWidth = 3;
// ഔട്ട്പുട്ട് അളവുകൾ കണക്കാക്കുക
const outputHeight = inputHeight - kernelHeight + 1;
const outputWidth = inputWidth - kernelWidth + 1;
const output = new Array(nOutChan * outputHeight * outputWidth).fill(0);
for (let i = 0; i < outputHeight; i++) {
for (let j = 0; j < outputWidth; j++) {
for (let outChan = 0; outChan < nOutChan; outChan++) {
let sum = 0;
// എല്ലാ ഇൻപുട്ട് ചാനലുകളിലും ഒറ്റ സ്ഥാനത്ത് ഫിൽട്ടർ പ്രയോഗിക്കുക
for (let inChan = 0; inChan < nInChan; inChan++) {
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
const inI =
inChan * (inputHeight * inputWidth) +
(i + row) * inputWidth +
(j + col);
const kI =
outChan * (nInChan * 3 * 3) +
inChan * (3 * 3) +
row * 3 +
col;
sum += inputData[inI] * kernel[kI];
}
}
}
sum += bias[outChan];
const outI =
outChan * (outputHeight * outputWidth) +
i * outputWidth +
j;
output[outI] = sum;
}
}
}
return output;
}
ഇത് അസുന്ദരമാണെന്ന് എനിക്കറിയാം. റഫറൻസിനായി ഇവിടെ ഇട്ടിരിക്കുന്നു. മാക്സ്പൂളിനായി ശ്രദ്ധിക്കുക:
function maxPool2d(nInChannels, inputData, inputHeight, inputWidth) {
if (inputData.length !== inputHeight * inputWidth * nInChannels) {
console.error("maxpool2d: അസാധുവായ ഇൻപുട്ട് ഉയരം/വീതി");
return;
}
const poolSize = 2;
const stride = 2;
const outputHeight = Math.floor((inputHeight - poolSize) / stride) + 1;
const outputWidth = Math.floor((inputWidth - poolSize) / stride) + 1;
const output = new Array(outputHeight * outputWidth * nInChannels).fill(0);
for (let chan = 0; chan < nInChannels; chan++) {
for (let i = 0; i < outputHeight; i++) {
for (let j = 0; j < outputWidth; j++) {
let m = 0;
for (let row = 0; row < poolSize; row++) {
for (let col = 0; col < poolSize; col++) {
const ind =
chan * (inputHeight * inputWidth) +
(i * stride + row) * inputWidth +
(j * stride + col);
m = Math.max(m, inputData[ind]);
}
}
const outI =
chan * (outputHeight * outputWidth) + i * outputWidth + j;
output[outI] = m;
}
}
}
return output;
}
അതെ, ഇൻഡെക്സ് കണക്കാക്കുന്ന ആ ഭീകരമായ കോഡുമായി ഞാൻ കൈകാര്യം ചെയ്യുന്നതിന്റെ ഒരേയൊരു കാരണം ബ്ലേസിംഗ് ഫാസ്റ്റ 🔥ജാവാസ്ക്രിപ്റ്റ്🔥 വെബ് ആപ്പ് പ്രകടനമാണ്. ഒടുവിൽ, എല്ലാം ഒന്നിപ്പിക്കുന്ന ഫംഗ്ഷൻ ഇതാ:
function evalConv(digit, weights) {
const [
[f1, fshape1], // കൺവ് ഫിൽട്ടർ ഭാരങ്ങൾ
[b1, bshape1], // കൺവ് ബയസ്
[f2, fshape2],
[b2, fbshape2],
[w, wshape], // fcn ഭാരങ്ങൾ
[b, bshape], // fcn ബയസ്
] = weights;
const x1 = conv2d(1, 32, digit, 28, 28, f1, b1).map(relu);
const x2 = maxPool2d(32, x1, 26, 26);
const x3 = conv2d(32, 64, x2, 13, 13, f2, b2).map(relu);
const x4 = maxPool2d(64, x3, 11, 11);
const x5 = matrixDot(w, x4, 10, 1600, 1600, 1);
const x6 = vsum(x5, b);
const out = softmax(x6);
return out;
}
## ഉപസംഹാരം
എല്ലാവരും ആപ്പ് ഉപയോഗിച്ച് ആസ്വദിക്കുമെന്ന് ഞാൻ പ്രതീക്ഷിക്കുന്നു. നിങ്ങൾക്ക് എന്തെങ്കിലും ചോദ്യങ്ങളോ ഫീഡ്ബാക്കോ ഉണ്ടെങ്കിൽ, താഴെ ഒരു കമന്റ് ഇടാൻ മടിക്കേണ്ട.