Nano-neuron - 7 fungsi JavaScript sederhana yang menunjukkan bagaimana mesin dapat "belajar"

Nano-neuron adalah versi neuron yang disederhanakan dari konsep jaringan saraf. Nano-neuron melakukan tugas yang paling sederhana dan dilatih untuk mengubah suhu dari derajat Celsius ke derajat Fahrenheit.


Kode NanoNeuron.js terdiri dari 7 fungsi JavaScript sederhana yang melibatkan pembelajaran, pelatihan, prediksi, dan propagasi sinyal model secara langsung dan mundur. Tujuan penulisan fungsi-fungsi ini adalah untuk memberikan pembaca sebuah penjelasan yang minimal dan mendasar (intuisi) tentang bagaimana, bagaimanapun, sebuah mesin dapat "belajar". Kode tidak menggunakan pustaka pihak ketiga. Seperti kata pepatah, hanya fungsi JavaScript "vanilla" yang sederhana.


Fungsi-fungsi ini sama sekali bukan panduan lengkap untuk pembelajaran mesin. Banyak konsep pembelajaran mesin hilang atau disederhanakan! Penyederhanaan ini diperbolehkan untuk tujuan tunggal - untuk memberikan pembaca pemahaman dan intuisi paling mendasar tentang bagaimana sebuah mesin dapat, pada prinsipnya, "belajar", sehingga, sebagai akibatnya, "MAGIC pembelajaran mesin" terdengar lebih dan lebih kepada pembaca sebagai "MATEMATIKA pembelajaran mesin".


Nanoneuron


Apa yang akan dipelajari oleh nano-neuron kami


Anda mungkin pernah mendengar tentang neuron dalam konteks jaringan saraf . Nano-neuron adalah versi yang disederhanakan dari neuron yang sama. Dalam contoh ini, kita akan menulis implementasinya dari awal. Untuk kesederhanaan, kami tidak akan membangun jaringan nano-neuron. Kami akan fokus pada pembuatan satu nano-neuron dan mencoba mengajarinya cara mengubah suhu dari derajat Celsius ke derajat Fahrenheit. Dengan kata lain, kami akan mengajarinya untuk memprediksi suhu dalam derajat Fahrenheit berdasarkan suhu dalam derajat Celsius.


Omong-omong, rumus untuk mengubah derajat Celcius ke derajat Fahrenheit adalah sebagai berikut:


Celsius ke fahrenheit


Tetapi saat ini, nano-neuron kami tidak tahu apa-apa tentang formula ini ...


Model nano-neuron


Mari kita mulai dengan membuat fungsi yang menggambarkan model nano-neuron kita. Model ini adalah hubungan linear sederhana antara x dan y , yang terlihat seperti ini: y = w * x + b . Sederhananya, nano-neuron kami adalah anak yang dapat menggambar garis lurus dalam sistem koordinat XY .


Variabel w dan b adalah parameter model. Sebuah nano-neuron hanya tahu dua parameter fungsi linear ini. Parameter-parameter ini adalah apa yang akan dipelajari oleh nano-neuron kami selama proses pelatihan.


Satu-satunya hal yang dapat dilakukan oleh nano-neuron pada tahap ini adalah untuk mensimulasikan hubungan linier. Dia melakukan ini dalam metode predict() , yang mengambil variabel x pada input dan memprediksi variabel y pada output. Tanpa sihir.


 function NanoNeuron(w, b) { this.w = w; this.b = b; this.predict = (x) => { return x * this.w + this.b; } } 

_ (... tunggu ... regresi linier adalah Anda, atau apa?) _


Konversi derajat Celcius ke derajat Fahrenheit


Suhu dalam derajat Celsius dapat dikonversi ke derajat Fahrenheit sesuai dengan rumus: f = 1.8 * c + 32 , di mana c adalah suhu dalam derajat Celsius dan f adalah suhu dalam derajat Fahrenheit.


 function celsiusToFahrenheit(c) { const w = 1.8; const b = 32; const f = c * w + b; return f; }; 

Sebagai hasilnya, kami ingin nano-neuron kami dapat mensimulasikan fungsi khusus ini. Dia harus menebak (mengetahui) bahwa parameter w = 1.8 dan b = 32 tanpa mengetahuinya terlebih dahulu.


Beginilah tampilan fungsi konversi pada bagan. Itulah yang harus dipelajari "bayi" nano-saraf kami untuk "menggambar":


Konversi Celsius ke fahrenheit


Pembuatan data


Dalam pemrograman klasik, kita tahu input data ( x ) dan algoritma untuk mengkonversi data ini (parameter w dan b ), tetapi data output ( y ) tidak diketahui. Output dihitung berdasarkan input menggunakan algoritma yang dikenal. Dalam pembelajaran mesin, sebaliknya, hanya data input dan output ( x dan y ) yang diketahui, tetapi algoritma untuk beralih dari x ke y diketahui (parameter w dan b ).


Ini adalah generasi input dan output yang akan kita lakukan sekarang. Kita perlu menghasilkan data untuk melatih model kita dan data untuk menguji model. Fungsi pembantu celsiusToFahrenheit() akan membantu kami dalam hal ini. Masing-masing set data pelatihan dan tes adalah satu set pasangan x dan y . Misalnya, jika x = 2 , maka y = 35,6 dan seterusnya.


Di dunia nyata, sebagian besar data kemungkinan dikumpulkan , bukan dihasilkan . Misalnya, data yang dikumpulkan tersebut dapat berupa serangkaian "foto wajah" -> "nama orang".

Kami akan menggunakan dataset PELATIHAN untuk melatih nano-neuron kami. Sebelum dia tumbuh dan mampu mengambil keputusan sendiri, kita harus mengajarinya apa yang "benar" dan apa yang "salah" menggunakan data "benar" dari set pelatihan.


Omong-omong, di sini prinsip kehidupan "sampah di pintu masuk - sampah di pintu keluar" jelas ditelusuri. Jika nano-neuron melemparkan "kebohongan" ke dalam kit pelatihan bahwa 5 ° C dikonversi menjadi 1000 ° F, maka setelah banyak iterasi pelatihan, ia akan percaya ini dan akan dengan benar mengkonversi semua nilai suhu kecuali 5 ° C. Kita harus sangat berhati-hati dengan data pelatihan yang kita muat setiap hari ke dalam jaringan saraf otak kita.

Terganggu. Mari kita lanjutkan.


Kami akan menggunakan set data TEST untuk menilai seberapa baik nano-neuron kami telah dilatih dan dapat membuat prediksi yang benar pada data baru yang tidak dia lihat selama pelatihannya.


 function generateDataSets() { // xTrain -> [0, 1, 2, ...], // yTrain -> [32, 33.8, 35.6, ...] const xTrain = []; const yTrain = []; for (let x = 0; x < 100; x += 1) { const y = celsiusToFahrenheit(x); xTrain.push(x); yTrain.push(y); } // xTest -> [0.5, 1.5, 2.5, ...] // yTest -> [32.9, 34.7, 36.5, ...] const xTest = []; const yTest = []; //   0.5    1,       //   ,       . for (let x = 0.5; x < 100; x += 1) { const y = celsiusToFahrenheit(x); xTest.push(x); yTest.push(y); } return [xTrain, yTrain, xTest, yTest]; } 

Estimasi kesalahan prediksi


Kita membutuhkan metrik tertentu (pengukuran, jumlah, peringkat) yang akan menunjukkan seberapa dekat prediksi nano-neuron dengan true. Dengan kata lain, angka / metrik / fungsi ini harus menunjukkan seberapa benar atau salahnya neuron nano. Seperti di sekolah, seorang siswa bisa mendapat nilai 5 atau 2 untuk kendalinya.


Dalam kasus nano-neuron, kesalahannya (kesalahan) antara nilai sebenarnya dari y dan nilai prediction akan dihasilkan oleh rumus:


Biaya prediksi


Seperti dapat dilihat dari rumus, kita akan menganggap kesalahan sebagai perbedaan sederhana antara kedua nilai. Semakin dekat nilainya satu sama lain, semakin kecil perbedaannya. Kami menggunakan kuadrat di sini untuk menyingkirkan tanda, sehingga pada akhirnya (1 - 2) ^ 2 setara dengan (2 - 1) ^ 2 . Pembagian dengan 2 terjadi semata-mata untuk menyederhanakan makna turunan dari fungsi ini dalam rumus untuk propagasi kembali sinyal (lebih lanjut tentang ini di bawah).


Fungsi kesalahan dalam hal ini akan terlihat seperti ini:


 function predictionCost(y, prediction) { return (y - prediction) ** 2 / 2; // ie -> 235.6 } 

Perambatan sinyal langsung


Perambatan sinyal langsung melalui model kami berarti membuat prediksi untuk semua pasangan dari yTrain data pelatihan yTrain dan yTrain dan menghitung rata-rata kesalahan (error) dari prediksi ini.


Kami hanya membiarkan nano-neuron kami "berbicara", memungkinkannya untuk membuat prediksi (mengkonversi suhu). Pada saat yang sama, nano-neuron pada tahap ini bisa sangat salah. Nilai rata-rata kesalahan prediksi akan menunjukkan kepada kita seberapa jauh model kita / mendekati kebenaran saat ini. Nilai kesalahan sangat penting di sini, karena dengan mengubah parameter w dan b dan propagasi sinyal langsung lagi, kita dapat mengevaluasi apakah nano-neuron kita telah menjadi "lebih pintar" dengan parameter baru atau tidak.


Kesalahan prediksi rata-rata nano-neuron akan dilakukan menggunakan rumus berikut:


Biaya rata-rata


Di mana m adalah jumlah salinan pelatihan (dalam kasus kami, kami memiliki 100 pasangan data).


Inilah cara kami dapat menerapkan ini dalam kode:


 function forwardPropagation(model, xTrain, yTrain) { const m = xTrain.length; const predictions = []; let cost = 0; for (let i = 0; i < m; i += 1) { const prediction = nanoNeuron.predict(xTrain[i]); cost += predictionCost(yTrain[i], prediction); predictions.push(prediction); } //     . cost /= m; return [predictions, cost]; } 

Propagasi Balik Sinyal


Sekarang kita tahu bagaimana nano-neuron kita benar atau salah dalam prediksi (berdasarkan nilai rata-rata kesalahan), bagaimana kita bisa membuat prediksi lebih akurat?


Perambatan sinyal terbalik akan membantu kita dalam hal ini. Perambatan kembali sinyal adalah proses mengevaluasi kesalahan dari nano-neuron dan kemudian menyesuaikan parameternya w dan b sehingga prediksi nano-neuron berikutnya untuk seluruh rangkaian data pelatihan menjadi sedikit lebih akurat.


Di sinilah pembelajaran mesin menjadi seperti sihir. Konsep kunci di sini adalah turunan dari fungsi , yang menunjukkan ukuran langkah apa dan ke arah mana kita perlu mengambil untuk mendekati minimum fungsi (dalam kasus kami, minimum fungsi kesalahan).


Tujuan akhir pelatihan nano-neuron adalah untuk menemukan minimum fungsi kesalahan (lihat fungsi di atas). Jika kita dapat menemukan nilai w dan b di mana nilai rata-rata dari fungsi kesalahan kecil, maka ini berarti nano-neuron kita dapat mengatasi prediksi suhu dalam derajat Fahrenheit dengan baik.


Derivatif adalah topik besar dan terpisah yang tidak akan kita bahas dalam artikel ini. MathIsFun adalah sumber yang bagus yang dapat memberikan pemahaman dasar tentang turunan.


Satu hal yang harus kita pelajari dari esensi derivatif dan yang akan membantu kita memahami bagaimana backpropagation sinyal bekerja adalah bahwa turunan dari suatu fungsi pada titik x dan y , menurut definisi, adalah garis singgung pada kurva fungsi ini di x dan y dan menunjukkan kita arah ke minimum fungsi .


Kemiringan turunan


Gambar diambil dari MathIsFun


Misalnya, dalam grafik di atas, Anda melihat bahwa pada titik (x=2, y=4) kemiringan garis singgung menunjukkan kepada kita bahwa kita perlu bergerak ke dan ke untuk mencapai minimum fungsi. Juga perhatikan bahwa semakin besar kemiringan garis singgung, semakin cepat kita harus bergerak ke titik minimum.


Turunan dari fungsi rata-rata kesalahan rata-rata averageCost dengan parameter w dan b akan terlihat seperti ini:


dW


dB


Di mana m adalah jumlah salinan pelatihan (dalam kasus kami, kami memiliki 100 pasangan data).


Anda dapat membaca lebih detail tentang cara mengambil turunan dari fungsi kompleks di sini .


 function backwardPropagation(predictions, xTrain, yTrain) { const m = xTrain.length; //           'w'  'b'. //      0. let dW = 0; let dB = 0; for (let i = 0; i < m; i += 1) { dW += (yTrain[i] - predictions[i]) * xTrain[i]; dB += yTrain[i] - predictions[i]; } //    . dW /= m; dB /= m; return [dW, dB]; } 

Pelatihan model


Sekarang kita tahu bagaimana memperkirakan kesalahan / kesalahan prediksi model nano-neuron kami untuk semua data pelatihan (propagasi sinyal langsung). Kita juga tahu bagaimana menyesuaikan parameter w dan b model nano-neuron (propagasi balik sinyal) untuk meningkatkan akurasi prediksi. Masalahnya adalah jika kita melakukan propagasi sinyal maju dan mundur hanya sekali, maka ini tidak akan cukup bagi model kita untuk mengidentifikasi dan mempelajari dependensi dan hukum dalam data pelatihan. Anda dapat membandingkan ini dengan kunjungan sekolah satu hari siswa. Dia harus pergi ke sekolah secara teratur, hari demi hari, tahun demi tahun, untuk mempelajari semua materi.


Jadi, kita harus mengulangi propagasi maju dan mundur sinyal berkali-kali. Inilah yang dilakukan trainModel() . Dia seperti "guru" untuk model nano-neuron kami:


  • dia akan menghabiskan waktu ( epochs ) dengan nano-neuron kita yang masih konyol, mencoba untuk melatihnya,
  • dia akan menggunakan buku-buku khusus ( yTrain data yTrain dan yTrain ) untuk pelatihan,
  • itu mendorong "siswa" kami untuk belajar lebih rajin (lebih cepat) menggunakan parameter alpha , yang pada dasarnya mengendalikan kecepatan belajar.

Beberapa kata tentang parameter alpha . Ini hanya koefisien (pengganda) untuk nilai-nilai variabel dW dan dB , yang kami hitung selama propagasi belakang sinyal. Jadi, turunannya menunjukkan kepada kita arah ke minimum fungsi kesalahan (tanda-tanda nilai dW dan dB memberi tahu kita tentang hal ini). Derivatif juga menunjukkan kepada kita seberapa cepat kita perlu bergerak menuju minimum fungsi (nilai absolut dW dan dB memberi tahu kita tentang hal ini). Sekarang kita perlu mengalikan ukuran langkah dengan alpha untuk menyesuaikan kecepatan pendekatan kita ke minimum (ukuran langkah total). Kadang-kadang, jika kita menggunakan nilai besar untuk alpha , kita bisa melakukan langkah besar sehingga kita hanya bisa melangkahi minimum dari fungsi, sehingga melewatkannya.


Dengan analogi dengan "guru", semakin kuat dia akan memaksa "siswa-nano" kita untuk belajar, semakin cepat dia akan belajar, TETAPI, jika Anda memaksakan dan menekannya dengan sangat keras, "siswa-nano" kita mungkin mengalami gangguan saraf dan sepenuhnya apatis dan dia tidak akan belajar apa pun.


Kami akan memperbarui parameter model kami w dan b sebagai berikut:


w


b


Dan inilah bagaimana pelatihan itu sendiri terlihat:


 function trainModel({model, epochs, alpha, xTrain, yTrain}) { //     -.  . const costHistory = []; //    ()  for (let epoch = 0; epoch < epochs; epoch += 1) { //   . const [predictions, cost] = forwardPropagation(model, xTrain, yTrain); costHistory.push(cost); //   . const [dW, dB] = backwardPropagation(predictions, xTrain, yTrain); //    -,    . nanoNeuron.w += alpha * dW; nanoNeuron.b += alpha * dB; } return costHistory; } 

Menyatukan semua fitur


Waktu untuk menggunakan semua fungsi yang dibuat sebelumnya bersama-sama.


Buat instance dari model nano-neuron. Saat ini, nano-neuron tidak tahu apa-apa tentang parameter w dan b . Jadi mari kita atur w dan b secara acak.


 const w = Math.random(); // ie -> 0.9492 const b = Math.random(); // ie -> 0.4570 const nanoNeuron = new NanoNeuron(w, b); 

Kami menghasilkan set pelatihan dan data uji.


 const [xTrain, yTrain, xTest, yTest] = generateDataSets(); 

Sekarang mari kita coba latih model kita menggunakan langkah-langkah kecil ( 0.0005 ) untuk 70000 era. Anda dapat bereksperimen dengan parameter ini, mereka ditentukan secara empiris.


 const epochs = 70000; const alpha = 0.0005; const trainingCostHistory = trainModel({model: nanoNeuron, epochs, alpha, xTrain, yTrain}); 

Mari kita periksa bagaimana nilai kesalahan model kami berubah selama pelatihan. Kami berharap bahwa nilai kesalahan setelah pelatihan harus jauh lebih sedikit daripada sebelum pelatihan. Ini berarti nano-neuron kita lebih bijaksana. Pilihan sebaliknya juga dimungkinkan, ketika setelah pelatihan, kesalahan prediksi hanya meningkat (misalnya, nilai besar dari langkah alpha pembelajaran).


 console.log('  :', trainingCostHistory[0]); // ie -> 4694.3335043 console.log('  :', trainingCostHistory[epochs - 1]); // ie -> 0.0000024 

Dan di sini adalah bagaimana nilai kesalahan model berubah selama pelatihan. Pada sumbu x adalah zaman (dalam ribuan). Kami berharap grafik akan menurun.


Proses pelatihan


Mari kita lihat parameter apa yang dipelajari nano-neuron kita. Kami berharap bahwa parameter w dan b akan mirip dengan parameter dengan nama yang sama dari fungsi celsiusToFahrenheit() ( w = 1.8 dan b = 32 ), karena itu adalah nano-neuron yang saya coba simulasikan.


 console.log(' -:', {w: nanoNeuron.w, b: nanoNeuron.b}); // ie -> {w: 1.8, b: 31.99} 

Seperti yang Anda lihat, nano-neuron sangat dekat dengan fungsi celsiusToFahrenheit() .


Sekarang mari kita lihat seberapa akurat prediksi nano-neuron kita untuk data uji yang tidak dia lihat selama pelatihan. Kesalahan prediksi untuk data uji harus dekat dengan kesalahan prediksi untuk data pelatihan. Ini berarti bahwa nano-neuron telah mempelajari dependensi yang benar dan dapat dengan benar mengabstraksikan pengalamannya dari data yang sebelumnya tidak diketahui (ini adalah nilai keseluruhan model).


 [testPredictions, testCost] = forwardPropagation(nanoNeuron, xTest, yTest); console.log('   :', testCost); // ie -> 0.0000023 

Sekarang, karena "nano-baby" kami terlatih dengan baik di "sekolah" dan sekarang tahu bagaimana mengkonversi derajat Celsius ke derajat Fahrenheit secara akurat bahkan untuk data yang tidak dia lihat, kita dapat memanggilnya "cukup pintar". Sekarang kita bahkan bisa meminta saran padanya tentang konversi suhu, dan itulah tujuan dari seluruh pelatihan.


 const tempInCelsius = 70; const customPrediction = nanoNeuron.predict(tempInCelsius); console.log(`- "",  ${tempInCelsius}°C   :`, customPrediction); // -> 158.0002 console.log('  :', celsiusToFahrenheit(tempInCelsius)); // -> 158 

Sangat dekat! Seperti orang lain, nano-neuron kami baik, tetapi tidak sempurna :)


Pengodean yang berhasil!


Cara menjalankan dan menguji nano-neuron


Anda dapat mengkloning repositori dan menjalankan nano neuron secara lokal:


 git clone https://github.com/trekhleb/nano-neuron.git cd nano-neuron 

 node ./NanoNeuron.js 

Konsep yang terlewatkan


Konsep pembelajaran mesin berikut telah dihilangkan atau disederhanakan untuk kemudahan penjelasan.


Pemisahan set pelatihan dan data uji


Biasanya Anda memiliki satu set data besar. Bergantung pada jumlah salinan dalam set ini, pembagiannya ke dalam set pelatihan dan tes dapat dilakukan dalam proporsi 70/30. Data di set harus dicampur secara acak sebelum dipisah. Jika jumlah data besar (misalnya, jutaan), maka pembagian ke dalam set tes dan pelatihan dapat dilakukan dalam proporsi mendekati 90/10 atau 95/5.


Kekuatan online


Biasanya Anda tidak akan menemukan kasus ketika hanya satu neuron yang digunakan. Kekuatan ada di jaringan neuron semacam itu. Jaringan saraf dapat mempelajari ketergantungan yang jauh lebih kompleks.


Juga dalam contoh di atas, nano-neuron kami mungkin terlihat lebih seperti regresi linier sederhana daripada jaringan saraf.


Input Normalisasi


Sebelum pelatihan, biasanya untuk menormalkan data input .


Implementasi vektor


Untuk jaringan saraf, perhitungan vektor (matriks) jauh lebih cepat daripada perhitungan for loop. Biasanya propagasi sinyal langsung dan mundur dilakukan menggunakan operasi matriks menggunakan, misalnya, perpustakaan Python Numpy .


Fungsi Kesalahan Minimum


Fungsi kesalahan yang kami gunakan untuk neuron nano sangat sederhana. Itu harus mengandung komponen logaritmik . Suatu perubahan dalam rumus untuk fungsi kesalahan juga akan memerlukan perubahan dalam formula untuk perambatan sinyal maju dan mundur.


Fungsi aktivasi


Biasanya nilai output neuron melewati fungsi aktivasi. Untuk aktivasi, fungsi-fungsi seperti Sigmoid , ReLU dan lainnya dapat digunakan.

Source: https://habr.com/ru/post/id479220/


All Articles