Dalam
bab terakhir, kami melihat bagaimana jaringan saraf dapat secara mandiri mempelajari bobot dan offset menggunakan algoritma gradient descent. Namun, ada celah dalam penjelasan kami: kami tidak membahas perhitungan gradien fungsi biaya. Dan ini celah yang layak! Dalam bab ini, saya akan memperkenalkan algoritma cepat untuk menghitung gradien tersebut, yang dikenal sebagai propagasi balik.
Algoritma backpropagation pertama kali ditemukan pada tahun 1970-an, tetapi pentingnya tidak sepenuhnya dipahami sampai karya terkenal tahun 1986, yang ditulis oleh David Rumelhart, Joffrey Hinton dan Ronald Williams. Makalah ini menjelaskan beberapa jaringan saraf di mana backpropagation bekerja jauh lebih cepat daripada dalam pendekatan sebelumnya untuk belajar, itulah sebabnya mengapa dimungkinkan untuk menggunakan jaringan saraf untuk memecahkan masalah yang sebelumnya tidak dapat diselesaikan. Saat ini, algoritma backpropagation adalah pekerja keras untuk mempelajari jaringan saraf.
Bab ini berisi lebih banyak matematika daripada semua orang di buku ini. Jika Anda tidak terlalu menyukai matematika, Anda mungkin tergoda untuk melewati bab ini dan hanya memperlakukan distribusi kembali sebagai kotak hitam, detail yang siap Anda abaikan. Mengapa membuang waktu mempelajarinya?
Alasannya, tentu saja, adalah pengertian. Perambatan balik didasarkan pada ekspresi turunan parsial ∂C / ∂w dari fungsi biaya C sehubungan dengan bobot w (atau bias b) dari jaringan. Ekspresi menunjukkan seberapa cepat nilai berubah ketika bobot dan offset berubah. Dan meskipun ungkapan ini cukup kompleks, ia memiliki keindahannya sendiri, karena masing-masing unsurnya memiliki interpretasi yang alami dan intuitif. Karena itu, backpropagation bukan hanya algoritma pembelajaran cepat. Ini memberi kita pemahaman terperinci tentang bagaimana mengubah bobot dan offset mengubah semua perilaku jaringan. Dan layak untuk mempelajari detailnya.
Mengingat semua ini, jika Anda hanya ingin membuka bab ini atau melompat ke bab berikutnya, tidak apa-apa. Saya menulis sisa buku ini sehingga bisa dimengerti, bahkan jika kita menganggap distribusi terbalik sebagai kotak hitam. Tentu saja, nanti dalam buku ini akan ada saat-saat dari mana saya membuat referensi ke hasil bab ini. Tetapi pada saat itu, Anda harus memahami kesimpulan dasar, bahkan jika Anda tidak mengikuti semua argumen.
Untuk pemanasan: pendekatan matriks cepat untuk menghitung output dari jaringan saraf
Sebelum membahas backpropagation, mari kita dapatkan algoritma matriks cepat untuk menghitung output dari jaringan saraf. Kami sebenarnya sudah bertemu algoritma ini pada akhir bab sebelumnya, tapi saya jelaskan dengan cepat, jadi ada baiknya mempertimbangkan lagi secara lebih rinci. Secara khusus, ini akan menjadi cara yang baik untuk beradaptasi dengan catatan yang digunakan dalam distribusi kembali, tetapi dalam konteks yang akrab.
Mari kita mulai dengan catatan yang memungkinkan kita menunjukkan dengan jelas bobot di internet. Kita akan menggunakan
wljk untuk menunjukkan bobot koneksi neuron No. k di lapisan No. (l-1) dengan neuron No. j di lapisan No. l. Jadi, misalnya, diagram di bawah ini menunjukkan berat koneksi dari neuron keempat dari lapisan kedua dengan neuron kedua dari lapisan ketiga:

Pada awalnya, rekaman seperti itu terasa canggung, dan mengharuskan beberapa orang membiasakan diri. Namun, segera itu akan tampak sederhana dan alami bagi Anda. Salah satu fitur-fiturnya adalah urutan indeks j dan k. Anda dapat memutuskan bahwa akan lebih masuk akal untuk menggunakan j untuk menunjuk neuron input, dan k - untuk neuron output, dan bukan sebaliknya, seperti yang kita miliki. Saya akan menjelaskan alasan fitur ini di bawah ini.
Kami akan menggunakan notasi yang sama untuk offset dan aktivasi jaringan. Secara khusus, b
l j akan menunjukkan perpindahan neuron No. j di lapisan No. l. a
l j akan menunjukkan aktivasi neuron No. j di lapisan No. l. Diagram berikut menunjukkan contoh cara menggunakan entri ini:

Dengan catatan seperti itu, aktivasi
lj neuron No.
j di lapisan No. l dikaitkan dengan aktivasi di lapisan No. (l-1) dengan persamaan berikut (bandingkan dengan persamaan (4) dan pembahasannya dalam bab sebelumnya):
alj= sigma( sumkwljkal−1k+blj) tag23
di mana jumlah melewati semua neuron k di lapisan (l-1). Untuk menulis ulang ekspresi ini dalam bentuk matriks, kami mendefinisikan matriks bobot wl untuk setiap lapisan l. Elemen-elemen dari matriks bobot hanyalah bobot yang terhubung ke lapisan No. l, yaitu elemen dalam baris No. j dan kolom No. k akan menjadi
wl jk . Demikian pula, untuk setiap lapisan l kita mendefinisikan vektor perpindahan b
l . Anda mungkin menebak bagaimana ini bekerja - komponen vektor perpindahan hanya akan menjadi nilai b
lj , satu komponen untuk setiap neuron di lapisan No. l. Dan akhirnya, kita mendefinisikan vektor aktivasi a
l , yang komponennya adalah aktivasi a
l j .
Bahan terakhir yang dibutuhkan untuk menulis ulang (23) adalah bentuk matriks dari vektorisasi fungsi σ. Kami dengan santai menemukan vektorisasi pada bab terakhir - idenya adalah bahwa kami ingin menerapkan fungsi σ untuk setiap elemen vektor v. Kami menggunakan notasi yang jelas σ (v) untuk menunjukkan aplikasi elemen-bijaksana fungsi. Yaitu, komponen σ (v) hanyalah σ (v)
j = σ (v
j ). Sebagai contoh, jika kita memiliki fungsi f (x) = x
2 , maka bentuk vektor f memberikan kita
f( beginbmatrix23 endbmatrix)= beginbmatrixf(2)f(3) endbmatrix= beginbmatrix49 endbmatrix tag24
yaitu, f vektor hanya kuadrat setiap elemen vektor.
Dengan semua bentuk penulisan ini, persamaan (23) dapat ditulis ulang dalam bentuk vektor yang indah dan ringkas:
al= sigma(wlal−1+bl) tag25
Ungkapan seperti itu memungkinkan kita untuk melihat lebih global hubungan antara aktivasi satu lapisan dan aktivasi yang sebelumnya: kita cukup menerapkan matriks bobot untuk aktivasi, menambahkan vektor perpindahan, dan kemudian menerapkan sigmoid. Ngomong-ngomong, catatan inilah yang mengharuskan penggunaan catatan itu bersama-sama. Jika kita menggunakan indeks j untuk menunjukkan neuron input, dan k untuk neuron output, kita harus mengganti matriks bobot dalam persamaan (25) dengan yang ditransposisikan. Ini adalah perubahan kecil tapi menjengkelkan, dan kami akan kehilangan kesederhanaan pernyataan (dan refleksi) tentang "menerapkan matriks bobot untuk aktivasi". Pendekatan global semacam itu lebih sederhana dan lebih ringkas (dan menggunakan lebih sedikit indeks!) Dari pada pendekatan poneuron. Ini hanya cara untuk menghindari indeks neraka tanpa kehilangan keakuratan apa yang terjadi. Ungkapan ini juga berguna dalam praktik, karena sebagian besar pustaka matriks menawarkan cara cepat untuk melipatgandakan matriks, menambahkan vektor, dan membuat vektor. Kode di bab terakhir secara langsung menggunakan ungkapan ini untuk menghitung perilaku jaringan.
Menggunakan persamaan (25) untuk menghitung
l , kami menghitung nilai antara zl ≡ w
l a
l - 1 + b
l . Nilai ini cukup berguna untuk penamaan: kita sebut z
l input neuron berbobot dari lapisan No. l. Nanti kita akan secara aktif menggunakan input tertimbang ini. Persamaan (25) kadang-kadang ditulis melalui input tertimbang, sebagai
l = σ (z
l ). Perlu dicatat juga bahwa z
l memiliki komponen
zlj= sumkwljkal−1k+blj yaitu, zlj hanyalah input tertimbang dari fungsi aktivasi neuron j di lapisan l.
Dua asumsi penting tentang fungsi biaya
Tujuan backpropagation adalah untuk menghitung turunan parsial ∂C / ∂w dan ∂C / ∂b dari fungsi biaya C untuk setiap bobot w dan bias b dari jaringan. Agar backpropagation berfungsi, kita perlu membuat dua asumsi utama tentang bentuk fungsi biaya. Namun, sebelum itu akan berguna untuk membayangkan contoh fungsi biaya. Kami menggunakan fungsi kuadrat dari bab sebelumnya (persamaan (6)). Pada entri dari bagian sebelumnya, akan terlihat seperti
C= frac12n sumx||y(x)−aL(x)||2 tag26
di mana: n adalah jumlah total contoh pelatihan; jumlah berlaku untuk semua contoh x; y = y (x) adalah output yang dibutuhkan; L menunjukkan jumlah lapisan dalam jaringan; a
L = a
L (x) adalah vektor output dari aktivasi jaringan ketika x berada di input.
Oke, jadi asumsi seperti apa yang kita butuhkan tentang fungsi biaya C untuk menerapkan backpropagation? Pertama, fungsi biaya dapat ditulis sebagai rata-rata C = 1 / n
x C
x dari fungsi biaya C
x untuk contoh pelatihan individu x. Ini dilakukan dalam kasus fungsi biaya kuadratik, di mana biaya satu contoh pelatihan adalah C
x = 1/2 || y - a
L ||
2 . Asumsi ini akan berlaku untuk semua fungsi biaya lain yang akan kita temui dalam buku ini.
Kita memerlukan asumsi ini karena sebenarnya propagasi belakang memungkinkan kita untuk menghitung turunan parsial ∂C / ∂w dan ∂C / ∂b, rata-rata dari contoh pelatihan. Menerima asumsi ini, kami mengasumsikan bahwa contoh pelatihan x sudah diperbaiki, dan berhenti menentukan indeks x, menuliskan nilai C
x sebagai C. Kemudian kami akan mengembalikan x, tetapi untuk saat ini lebih baik hanya bersungguh-sungguh.
Asumsi kedua mengenai fungsi biaya - dapat ditulis sebagai fungsi dari output jaringan saraf:

Misalnya, fungsi biaya kuadrat memenuhi persyaratan ini, karena biaya kuadrat dari satu contoh pelatihan x dapat ditulis sebagai
C=1/2||y−aL||2=1/2 sumj(yj−aLj)2 tag27
yang akan menjadi fungsi aktivasi keluaran. Tentu saja, fungsi biaya ini juga tergantung pada output y yang diinginkan, dan Anda mungkin bertanya-tanya mengapa kami tidak menganggap C sebagai fungsi juga dari y. Namun, ingat bahwa contoh pelatihan input x sudah diperbaiki, jadi output y juga sudah diperbaiki. Secara khusus, kita tidak dapat mengubahnya dengan mengubah bobot dan perpindahan, yaitu, ini bukan yang dipelajari jaringan saraf. Oleh karena itu, masuk akal untuk mempertimbangkan C sebagai fungsi dari hanya aktivasi keluaran
L , dan y hanya sebagai parameter yang membantu untuk menentukannya.
Karya Hadamard s⊙t
Algoritma backpropagation didasarkan pada operasi biasa aljabar linier - penambahan vektor, perkalian vektor dengan matriks, dll. Namun, salah satu operasi lebih jarang digunakan. Misalkan s dan t adalah dua vektor dari dimensi yang sama. Kemudian dengan s wet kita menyatakan penggandaan elemen dari dua vektor. Maka komponen s⊙t hanyalah (s⊙t)
j = s jt
j . Sebagai contoh:
beginbmatrix12 endbmatrix odot beginbmatrix34 endbmatrix= beginbmatrix1∗32∗4 endbmatrix= beginbmatrix38 endbmatrix tag28
Pekerjaan sesekali semacam itu kadang-kadang disebut
karya Hadamard atau karya Schur. Kami akan menyebutnya karya Hadamard. Perpustakaan yang baik untuk bekerja dengan matriks biasanya memiliki implementasi cepat dari produk Hadamard, dan ini bisa nyaman ketika menerapkan backpropagation.
Empat persamaan mendasar untuk propagasi balik
Backpropagation melibatkan pemahaman bagaimana mengubah bobot dan offset jaringan mengubah fungsi biaya. Intinya, ini berarti menghitung turunan parsial ∂C / ∂w
l jk dan ∂C / ∂b
l j . Tetapi untuk perhitungannya, pertama-tama kita menghitung nilai antara δ
l j , yang kita sebut kesalahan pada neuron No. j di lapisan No. l. Propagasi belakang akan memberi kita prosedur untuk menghitung kesalahan δ
l j , dan kemudian mengasosiasikan δ
l j dengan ∂C / ∂w
l jk dan ∂C / ∂b
l j .
Untuk memahami bagaimana kesalahan ditentukan, bayangkan bahwa iblis telah mulai di jaringan saraf kita:

Dia duduk di neuron No. j di lapisan No. l. Setelah menerima data input, daemon mengganggu operasi neuron. Ini menambahkan perubahan kecil dalam Δz lj ke input neuron yang berbobot, dan bukannya menghasilkan σ (z
lj ), neuron akan menghasilkan σ (z
l j + Δz
l j ). Perubahan ini juga akan menyebar melalui lapisan jaringan berikut, yang pada akhirnya akan mengubah total biaya dengan (∂C / ∂z
l j ) * Δz
l j .
Tapi iblis kami baik, dan dia berusaha membantu Anda meningkatkan biaya, yaitu, menemukan lz lj yang mengurangi biaya. Misalkan nilai ∂C / ∂z lj besar (positif atau negatif). Maka iblis dapat secara serius mengurangi biaya dengan memilih Δz
l j dengan tanda yang berlawanan dengan ∂C / ∂z
l j . Tetapi jika ∂C / ∂z lj mendekati nol, maka iblis tidak dapat sangat meningkatkan biaya dengan mengubah input tertimbang
zlj . Jadi, dari sudut pandang iblis, neuron sudah mendekati optimal (ini, tentu saja, hanya berlaku untuk Δz
l j kecil . Misalkan ini adalah batasan dari tindakan iblis). Oleh karena itu, dalam arti heuristik, ∂C / ∂z
l j adalah ukuran kesalahan neuron.
Di bawah motivasi dari cerita ini, kami mendefinisikan kesalahan δ
l j dari neuron j di lapisan l, sebagai
deltalj equiv frac partialC partialzlj tag29
Dengan konvensi kami yang biasa, kami menggunakan δ
l untuk menunjukkan vektor kesalahan yang terkait dengan lapisan l. Kembali propagasi akan memberi kita cara untuk menghitung δ
l untuk setiap lapisan, dan kemudian menghubungkan kesalahan ini dengan jumlah yang benar-benar menarik bagi kita, ∂C / ∂w
l jk dan ∂C / ∂b
l j .
Anda mungkin bertanya-tanya mengapa daemon mengubah input tertimbang z
l j . Lagi pula, akan lebih alami untuk membayangkan bahwa iblis mengubah aktivasi output a lj sehingga kita menggunakan ∂C / ∂a
l j sebagai ukuran kesalahan. Bahkan, jika Anda melakukannya, maka semuanya ternyata sangat mirip dengan apa yang akan kita bahas lebih lanjut. Namun, dalam hal ini, representasi backpropagation akan sedikit lebih rumit secara aljabar. Oleh karena itu, kita memikirkan varian δ
l j = ∂C / ∂z
l j sebagai ukuran kesalahan.
Dalam masalah klasifikasi, istilah "kesalahan" terkadang berarti jumlah klasifikasi yang salah. Misalnya, jika jaringan saraf dengan benar mengklasifikasikan 96,0% dari angka, maka kesalahannya adalah 4,0%. Jelas, ini sama sekali bukan yang kita maksud dengan vektor δ. Namun dalam praktiknya, Anda biasanya dapat dengan mudah memahami makna yang dimaksud.
Rencana Serangan : Backpropagation didasarkan pada empat persamaan mendasar. Bersama-sama, mereka memberi kita cara untuk menghitung kesalahan δ
l dan gradien fungsi biaya. Saya berikan di bawah. Tidak perlu mengharapkan perkembangan instan mereka. Anda akan kecewa. Persamaan backpropagation begitu dalam sehingga pemahaman yang baik membutuhkan waktu dan kesabaran yang nyata, dan pendalaman pertanyaan yang bertahap. Berita baiknya adalah bahwa kesabaran ini akan membuahkan hasil yang besar. Oleh karena itu, di bagian ini, alasan kami baru saja dimulai, membantu Anda mengikuti jalan pemahaman persamaan yang mendalam.
Berikut adalah diagram tentang bagaimana kita akan menyelidiki persamaan-persamaan ini nanti: Saya akan memberikan bukti singkat tentang mereka untuk membantu menjelaskan mengapa mereka benar; kami akan menulis ulang mereka dalam bentuk algoritmik dalam bentuk pseudocode, dan melihat bagaimana menerapkannya dalam kode python nyata; di bagian akhir bab ini, kita akan mengembangkan ide intuitif tentang makna persamaan backpropagation, dan bagaimana persamaan itu dapat ditemukan dari awal. Kami akan secara berkala kembali ke empat persamaan mendasar, dan semakin dalam Anda memahaminya, semakin nyaman dan mungkin indah serta alami mereka bagi Anda.
Persamaan kesalahan dari layer output, δ L : komponen δ
L dianggap sebagai
deltaLj= frac partialC partialaLj sigma′(zLj) tagBP1
Ekspresi yang sangat alami. Istilah pertama di sebelah kanan, ∂C / ∂a
L j , mengukur seberapa cepat perubahan biaya sebagai fungsi dari aktivasi keluaran No. j. Jika, misalnya, C tidak terlalu tergantung pada neuron output tertentu, maka δ
Lj akan kecil, seperti yang diharapkan. Istilah kedua di sebelah kanan, σ '(z
L j ), mengukur seberapa cepat fungsi aktivasi σ berubah dalam z
L j .
Perhatikan bahwa semua yang ada di (BP1) mudah untuk dihitung. Secara khusus, kami menghitung z
L j ketika menghitung perilaku jaringan, dan akan membutuhkan sedikit lebih banyak sumber daya untuk menghitung σ '(z
L j ). Tentu saja, bentuk persis ∂C / ∂a Lj tergantung pada bentuk fungsi biaya. Namun, jika fungsi biaya diketahui, maka seharusnya tidak ada masalah dengan penghitungan ∂C / ∂a
L j . Misalnya, jika kita menggunakan fungsi biaya kuadratik, maka C = 1/2
j (y
j - a
L j )
2 , oleh karena itu ∂C / ∂a
L j = (a
L j -
yj ), yang mudah untuk dihitung.
Persamaan (BP1) adalah ekspresi meledak dari δ
L. Ini benar-benar normal, tetapi tidak direkam dalam bentuk matriks, yang kami butuhkan untuk distribusi kembali. Namun, mudah untuk menulis ulang dalam bentuk matriks, karena
deltaL= nablaaC odot sigma′(zL) tagBP1a
Di sini ∇
a C didefinisikan sebagai vektor yang komponennya adalah turunan parsial ∂C / ∂a
L j . Ini dapat direpresentasikan sebagai ekspresi dari laju perubahan C sehubungan dengan aktivasi keluaran. Mudah untuk melihat bahwa persamaan (BP1a) dan (BP1) adalah setara, oleh karena itu kami akan menggunakan (BP1) untuk merujuk pada salah satu dari mereka di bawah ini. Misalnya, dalam kasus nilai kuadrat, kita memiliki ∇
a C = (a
L - y), sehingga bentuk matriks penuh (BP1) akan menjadi
deltaL=(aL−y) odot sigma′(zL) tag30
Segala sesuatu dalam ekspresi ini memiliki bentuk vektor yang nyaman, dan mudah untuk menghitung menggunakan perpustakaan seperti Numpy.
Ekspresi kesalahan δ l melalui kesalahan di lapisan berikutnya, δ l + 1 : khususnya,
deltal=((wl+1)T deltal+1) cdot sigma′(zl) tagBP2
di mana (w1
+ 1 )
T adalah transposisi dari matriks berat w1
+ untuk lapisan No. (l + 1). Persamaannya tampak rumit, tetapi setiap elemen mudah ditafsirkan. Misalkan kita tahu kesalahan δ
l +1 untuk layer (l + 1). Transposisi matriks bobot, (w
l + 1 )
T , dapat dibayangkan sebagai menggerakkan kesalahan ke belakang melalui jaringan, yang memberi kita beberapa ukuran kesalahan pada keluaran lapisan No. l. Maka kami mempertimbangkan produk Hadamard ⊙σ '(z
l ). Ini mendorong kesalahan kembali melalui fungsi aktivasi di lapisan l, memberi kita nilai kesalahan δl dalam input tertimbang untuk lapisan l.
Dengan menggabungkan (BP2) dengan (BP1), kita dapat menghitung kesalahan δ
l untuk setiap lapisan jaringan.
Kita mulai dengan menggunakan (BP1) untuk menghitung δ L , kemudian menggunakan persamaan (BP2) untuk menghitung δ L-1 , lalu lagi untuk menghitung δ L-2 , dan seterusnya, sampai ke bagian belakang jaringan.Persamaan tingkat perubahan biaya dalam kaitannya dengan offset apa pun dalam jaringan : khususnya:∂ C∂ b l j =δ l j
Yaitu, kesalahan δ l j persis sama dengan tingkat perubahan ∂C / ∂b l j . Ini luar biasa karena (BP1) dan (BP2) telah memberi tahu kami cara menghitung δ l j . Kami dapat menulis ulang (BP3) lebih pendek sebagai∂ C∂ b =δ
di mana δ diperkirakan untuk neuron yang sama dengan bias b.Persamaan untuk laju perubahan nilai dalam kaitannya dengan bobot apa pun dalam jaringan : khususnya:∂ C∂ w l j k =a l - 1 k δ l j
Dari sini kita belajar bagaimana menghitung turunan parsial ∂C / ∂w l jk melalui nilai δ l dan a -1 , metode perhitungan yang sudah kita ketahui. Persamaan ini dapat ditulis ulang dalam bentuk yang kurang dimuat:∂ C∂ w =ainδout
dimana di - aktivasi input saraf untuk berat badan w, dan delta keluar - kesalahan output saraf dari berat w. Jika Anda melihat lebih berat w dan dua neuron yang terhubung ke mereka, maka kita dapat menarik cara ini:
Pleasant konsekuensi dari persamaan (32) yang saat mengaktifkan di kecil, di ≈ 0, ∂C / ∂w gradien anggota juga cenderung ke nol. Dalam hal ini, kami katakan bahwa bobot dilatih secara lambat, artinya, tidak banyak berubah selama gradient descent. Dengan kata lain, salah satu konsekuensinya (BP4) adalah bahwa keluaran neuron dengan aktivasi yang rendah belajar lambat.Gagasan lain dapat diambil dari (BP1) - (BP4). Mari kita mulai dengan layer output. Pertimbangkan istilah σ '(z L j) di (BP1). Ingat dari grafik sigmoid dari bab terakhir yang menjadi datar ketika σ (z L j ) mendekati 0 atau 1. Dalam kasus ini, σ '(z L j ) ≈ 0. Oleh karena itu, berat pada lapisan terakhir akan dilatih secara perlahan jika aktivasi neuron output kecil (≈ 0) atau besar (≈ 1). Dalam hal ini, biasanya dikatakan bahwa neuron output jenuh, dan akibatnya, berat telah berhenti dilatih (atau sedang dilatih perlahan). Komentar yang sama berlaku untuk perpindahan neuron output.Gagasan serupa dapat diperoleh mengenai lapisan sebelumnya. Secara khusus, pertimbangkan istilah σ '(z l ) di (BP2). Ini berarti bahwa δ l jkemungkinan besar akan menjadi kecil saat neuron mendekati saturasi. Dan ini, pada gilirannya, berarti bahwa setiap bobot pada input neuron jenuh akan dilatih secara lambat (namun, ini tidak akan bekerja jika w l + 1 T δ l + 1 akan memiliki elemen yang cukup besar yang mengimbangi nilai kecil σ '(z L j )).Untuk meringkas: kami belajar bahwa berat akan dilatih secara lambat jika aktivasi dari neuron input kecil atau neuron output jenuh, yaitu, aktivasinya kecil atau besar.Ini tidak terlalu mengejutkan. Namun, pengamatan ini membantu meningkatkan pemahaman kita tentang apa yang terjadi ketika kita melatih jaringan. Selain itu, kita dapat mendekati argumen ini dari sisi lain. Keempat persamaan mendasar ini valid untuk fungsi aktivasi apa pun, dan tidak hanya untuk sigmoid standar (karena, seperti yang akan kita lihat nanti, properti tidak menggunakan sigmoid). Oleh karena itu, persamaan ini dapat digunakan untuk mengembangkan fungsi aktivasi dengan sifat pembelajaran tertentu yang diperlukan. Sebagai contoh, misalkan kita memilih fungsi aktivasi σ yang berbeda dari sigmoid, sehingga σ 'selalu positif dan tidak mendekati nol. Ini mencegah perlambatan belajar yang terjadi ketika neuron sigmoid normal jenuh. Kemudian dalam buku ini kita akan melihat contoh di mana fungsi aktivasi berubah dengan cara yang sama.Dengan adanya persamaan (BP1) - (BP4), kita dapat menjelaskan mengapa modifikasi seperti itu diperlukan, dan bagaimana mereka dapat mempengaruhi situasi.
:δL=Σ′(zL)∇aC
di mana Σ '(z L ) adalah matriks kuadrat dengan σ' (z L j ) terletak diagonal dan elemen lainnya adalah 0. Perhatikan bahwa matriks ini berinteraksi dengan ∇ a C melalui perkalian matriks yang biasa.Tunjukkan bahwa (BP2) dapat ditulis ulang sebagaiδ l = Σ ′ ( z l ) ( w l + 1 ) T δ l + 1
Menggabungkan tugas-tugas sebelumnya, menunjukkan bahwa:δ l = Σ ′ ( z l ) ( w l + 1 ) T … Σ ′ ( z L - 1 ) ( w L ) T Σ ′ ( z L ) ∇ a C
Untuk pembaca yang terbiasa dengan perkalian matriks, persamaan ini akan lebih mudah dipahami daripada (BP1) dan (BP2). Saya berkonsentrasi pada (BP1) dan (BP2) karena pendekatan ini lebih cepat untuk mengimplementasikan secara numerik. [di sini Σ bukan jumlah ((), tetapi modal σ (sigma) / kira-kira. perev. ]Bukti dari empat persamaan mendasar (bagian opsional)
Sekarang kami membuktikan empat persamaan mendasar (BP1) - (BP4). Semuanya adalah konsekuensi dari aturan rantai (aturan diferensiasi fungsi kompleks) dari analisis fungsi banyak variabel. Jika Anda terbiasa dengan aturan rantai, saya sangat merekomendasikan mencoba menghitung turunannya sendiri sebelum melanjutkan membaca.Mari kita mulai dengan persamaan (BP1), yang memberi kami sebuah pernyataan untuk delta kesalahan output dari L . Untuk membuktikannya, kami mengingatnya, dengan definisi:δ L j = ∂ C∂ z L j
Menerapkan aturan rantai, kami menulis ulang turunan parsial melalui turunan parsial dari aktivasi output:δ L j = ∑ k ∂ C∂ a L k ∂a L k∂ z L j
di mana penjumlahan berjalan di atas semua neuron k di lapisan output. Tentu saja, keluaran aktivasi sebuah L k neuron №k hanya bergantung pada masukan z tertimbang L j ke neuron №j, ketika k = j. Oleh karena itu, ∂a L k / ∂z L j menghilang ketika k ≠ j. Sebagai hasilnya, kami menyederhanakan persamaan sebelumnya menjadiδ L j = ∂ C∂ a L j ∂a L j∂ z L j
Mengingat bahwa a L j = σ (z L j ), kita dapat menulis ulang suku kedua di sebelah kanan sebagai σ '(z L j ), dan persamaannya berubah menjadiδ L j = ∂ C∂ a L j σ′(z L j )
yaitu, dalam (BP1) dalam tampilan yang meledak.Kemudian kita buktikan (BP2), yang memberikan persamaan untuk kesalahan δ l melalui kesalahan di lapisan berikutnya δ l + 1 . Untuk melakukan ini, kita perlu menulis ulang δ l j = ∂C / ∂z l j hingga δ l + 1 k = ∂C / ∂z l + 1 k . Ini dapat dilakukan dengan menggunakan aturan rantai:δ l j = ∂ C∂ z l j
= ∑ k ∂ C∂ z l + 1 k ∂z l + 1 k∂ z l j
= ∑ k ∂ z l + 1 k∂ z l j δ l + 1 k
di mana pada baris terakhir kita bertukar dua istilah di sebelah kanan, dan menggantikan definisi δ l + 1 k . Untuk menghitung suku pertama pada baris terakhir, perhatikan ituz l + 1 k = Σ j w l + 1 k j a l j + b l + 1 k = Σ j w l + 1 k j σ ( z l j ) + b l + 1 k
Membedakan, kita dapatkan∂ z l + 1 k∂ z l j =w l + 1 k j σ′(z l j ).
Mengganti ini menjadi (42), kita dapatkanδ l j = Σ k w l + 1 k j δ l + 1 k σ ' ( z l j ) .
Yaitu, (BP2) dalam entri yang meledak.Masih harus dibuktikan (BP3) dan (BP4). Mereka juga mengikuti dari aturan rantai, kira-kira sama dengan dua aturan sebelumnya. Saya akan menyerahkannya kepada Anda sebagai latihan.Latihan
- Buktikan (BP3) dan (BP4).
Itu semua bukti dari empat persamaan backpropagation mendasar. Ini mungkin terlihat rumit. Namun pada kenyataannya, ini hanyalah hasil penerapan hati-hati dari aturan rantai. Berbicara kurang ringkas, propagasi balik dapat dibayangkan sebagai cara menghitung gradien fungsi biaya melalui aplikasi sistematis aturan rantai dari analisis fungsi banyak variabel. Dan itu benar-benar semua itu distribusi kembali - sisanya hanya detail.Algoritma backpropagation
Persamaan backpropagation memberi kita metode untuk menghitung gradien fungsi biaya. Mari kita tulis ini secara eksplisit sebagai algoritma:- Input x: menetapkan aktivasi yang sesuai 1 untuk layer input.
- : l = 2,3,…,L z l = w l a l−1 +b l a l = σ(z l ).
- δ L : δ L = ∇ a C ⊙ σ'(z L ).
- : l = L−1,L−2,…,2 δ l = ((w l+1 ) T δ l+1 ) ⊙ σ'(z l ).
- : ∂C∂wljk=al−1kδlj dan ∂C∂blj=δlj .
Melihat algoritma, Anda akan mengerti mengapa itu disebut backpropagation. Kami menghitung vektor kesalahan δ l mundur, mulai dari lapisan terakhir. Mungkin terlihat aneh bahwa kita akan mundur melalui jaringan. Tetapi jika Anda berpikir tentang bukti propagasi balik, maka gerakan sebaliknya adalah konsekuensi dari kenyataan bahwa biaya adalah fungsi dari output jaringan. Untuk memahami bagaimana biaya bervariasi dengan bobot dan offset awal, kita perlu menerapkan aturan rantai berulang-ulang, kembali melalui lapisan untuk mendapatkan ekspresi yang berguna.Latihan
- . , , f(∑ j w j x j +b), f – , . ?
- . , σ(z) = z . .
Seperti yang saya jelaskan sebelumnya, algoritma backpropagation menghitung gradien fungsi biaya untuk satu contoh pelatihan, C = C x . Dalam praktiknya, propagasi balik sering dikombinasikan dengan algoritma pembelajaran, misalnya, dengan penurunan gradien stokastik, ketika kami menghitung gradien untuk banyak contoh pelatihan. Khususnya, untuk paket mini contoh pelatihan yang diberikan, algoritma berikut ini menerapkan penurunan gradien berdasarkan paket mini ini:- Pintu Masuk: Satu set contoh pelatihan.
- Untuk setiap contoh pelatihan x, tetapkan aktivasi input yang sesuai a , x, 1 dan lakukan langkah-langkah berikut:
- l=2,3,…,L z x,l = w l a x,l−1 +b l a x,l = σ(z x,l ).
- δ x,L : δ x,L = ∇ a C x ⋅ σ'(z x,L ).
- : l=L−1,L−2,…,2 δ x,l = ((w l+1 ) T δ x,l+1 ) ⋅ σ'(z x,l ).
- : l=L,L−1,…,2 wl rightarrowwl− frac etam sumx deltax,l(ax,l−1)T , dan offset sesuai aturan bl rightarrowbl− frac etam sumx deltax,l .
Tentu saja, untuk menerapkan penurunan gradien stokastik dalam praktiknya, Anda juga akan memerlukan siklus eksternal yang menghasilkan paket mini contoh pelatihan, dan siklus eksternal yang melewati beberapa era pelatihan. Untuk kesederhanaan, saya menghilangkannya.
Kode untuk distribusi kembali
Setelah memahami sisi abstrak dari backpropagation, kita sekarang dapat memahami kode yang digunakan pada bab sebelumnya yang mengimplementasikan backpropagation. Ingat dari bab itu bahwa kode itu terkandung dalam metode update_mini_batch dan backprop kelas Jaringan. Kode untuk metode ini adalah terjemahan langsung dari algoritma yang dijelaskan di atas. Secara khusus, metode update_mini_batch memperbarui bobot dan offset jaringan dengan menghitung gradien untuk contoh pelatihan mini_batch saat ini:
class Network(object): ... def update_mini_batch(self, mini_batch, eta): """ , -. mini_batch – (x, y), eta – .""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)]
Sebagian besar pekerjaan dilakukan oleh baris delta_nabla_b, delta_nabla_w = self.backprop (x, y), menggunakan metode backprop untuk menghitung turunan parsial ∂C
x / ∂b
l j dan ∂C
x / ∂w
l jk . Metode backprop hampir mengulangi algoritma dari bagian sebelumnya. Ada satu perbedaan kecil - kami menggunakan pendekatan yang sedikit berbeda untuk pengindeksan lapisan. Ini dilakukan untuk memanfaatkan fitur python, indeks array negatif yang memungkinkan Anda untuk menghitung elemen mundur dari akhir. l [-3] akan menjadi elemen ketiga dari akhir array l. Kode backprop diberikan di bawah ini, bersama dengan fungsi tambahan yang digunakan untuk menghitung sigmoid, turunan dan turunannya dari fungsi biaya. Dengan mereka, kode tersebut lengkap dan dapat dimengerti. Jika ada sesuatu yang tidak jelas, lihat deskripsi kode daftar lengkap pertama.
class Network(object): ... def backprop(self, x, y): """ ``(nabla_b, nabla_w)``, C_x. ``nabla_b`` ``nabla_w`` - numpy, ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights]
Tantangan
- Pendekatan backpropagation sepenuhnya berbasis matriks pada minipack. Implementasi kami dari penurunan gradien stokastik menggunakan serangkaian contoh pelatihan dari paket-mini. Algoritma backpropagation dapat diubah sehingga menghitung gradien untuk semua contoh pelatihan dari paket mini pada saat yang sama. Alih-alih memulai dengan satu vektor x, kita bisa mulai dengan matriks X = [x 1 x 2 ... x m ], yang kolomnya adalah vektor dari minipack. Distribusi langsung adalah melalui produk matriks berat, penambahan matriks yang cocok untuk perpindahan dan penggunaan luas sigmoid. Propagasi balik mengikuti pola yang sama. Tulis kode pseudo untuk pendekatan ini untuk algoritma backpropagation. Ubah network.py sehingga menggunakan pendekatan matriks ini. Keuntungan dari pendekatan ini adalah penggunaan semua keunggulan perpustakaan modern untuk aljabar linier. Sebagai hasilnya, ia dapat berjalan lebih cepat daripada siklus paket-mini (misalnya, di komputer saya program ini berakselerasi sekitar 2 kali pada tugas klasifikasi MNIST). Dalam praktiknya, semua perpustakaan serius untuk distribusi kembali menggunakan pendekatan matriks penuh atau versi tertentu.
Dalam hal apa propagasi balik merupakan algoritma yang cepat?
Dalam hal apa propagasi balik merupakan algoritma yang cepat? Untuk menjawab pertanyaan ini, pertimbangkan pendekatan lain untuk menghitung gradien. Bayangkan hari-hari awal penelitian jaringan saraf. Mungkin ini adalah tahun 1950-an atau 1960-an, dan Anda adalah orang pertama di dunia yang muncul dengan gagasan menggunakan gradient descent untuk pelatihan! Tetapi agar ini berfungsi, Anda perlu menghitung gradien fungsi biaya. Anda mengingat aljabar dan memutuskan untuk melihat apakah Anda dapat menggunakan aturan rantai untuk menghitung gradien. Setelah bermain sedikit, Anda melihat aljabar yang tampaknya sulit, dan Anda kecewa. Anda mencoba menemukan pendekatan yang berbeda. Anda memutuskan untuk mempertimbangkan biaya hanya sebagai fungsi dari bobot C = C (w) (kami akan kembali ke perpindahan beberapa saat kemudian). Anda menghitung bobot w
1 , w
2 , ... dan ingin menghitung ∂C / ∂w
j untuk bobot w
j . Cara yang jelas adalah dengan menggunakan aproksimasi
frac partialC partialwj approx fracC(w+ epsilonej)−C(w) epsilon tag46
Di mana ε> 0 adalah angka positif kecil, dan e
j adalah vektor arah satuan j. Dengan kata lain, kita dapat memperkirakan ∂C / ∂wj dengan menghitung biaya C untuk dua nilai wj yang sedikit berbeda, dan kemudian menerapkan persamaan (46). Gagasan yang sama memungkinkan kita menghitung turunan parsial ∂C / ∂b sehubungan dengan perpindahan.
Pendekatannya terlihat menjanjikan. Secara konsep sederhana, mudah diimplementasikan, hanya menggunakan beberapa baris kode. Itu terlihat jauh lebih menjanjikan daripada gagasan menggunakan aturan rantai untuk menghitung gradien!
Sayangnya, meskipun pendekatan ini terlihat menjanjikan, ketika diimplementasikan dalam kode, ternyata ini bekerja sangat lambat. Untuk memahami alasannya, bayangkan kita memiliki sejuta bobot dalam jaringan. Maka untuk setiap bobot w
j kita perlu menghitung C (w + εe
j ) untuk menghitung ∂C / ∂w
j . Dan ini berarti bahwa untuk menghitung gradien, kita perlu menghitung fungsi biaya sejuta kali, yang akan membutuhkan sejuta lintasan langsung melalui jaringan (untuk setiap contoh pelatihan). Dan kita juga perlu menghitung C (w), jadi kita mendapatkan satu juta dan satu melewati jaringan.
Trik backpropagation adalah memungkinkan kita untuk secara bersamaan menghitung semua turunan parsial ∂C / ∂w
j menggunakan hanya satu lintasan langsung melalui jaringan, diikuti oleh satu lintasan balik. Secara kasar, biaya komputasi dari pass kembali hampir sama dengan biaya langsung.
Oleh karena itu, total biaya propagasi balik kira-kira sama dengan dua lintasan langsung melalui jaringan. Bandingkan ini dengan jutaan dan satu izin langsung yang diperlukan untuk menerapkan metode (46)! Jadi, meskipun backpropagation terlihat seperti pendekatan yang lebih rumit, pada kenyataannya itu jauh lebih cepat.
Untuk pertama kalinya akselerasi ini dihargai sepenuhnya pada tahun 1986, dan ini secara dramatis memperluas berbagai tugas yang diselesaikan dengan bantuan jaringan saraf. Pada gilirannya, ini telah menyebabkan peningkatan jumlah orang yang menggunakan jaringan saraf. Tentu saja, backpropagation bukanlah obat mujarab. Bahkan pada akhir 1980-an, orang menemukan keterbatasannya, terutama ketika mencoba menggunakan propagasi balik untuk melatih jaringan saraf yang dalam, yaitu jaringan dengan banyak lapisan tersembunyi. Nanti kita akan melihat bagaimana komputer modern dan ide-ide rumit baru memungkinkan untuk menggunakan backpropagation untuk melatih jaringan saraf yang begitu dalam.
Distribusi terbalik: secara umum
Seperti yang telah saya jelaskan, propagasi balik mengungkapkan dua misteri kepada kita. Hal pertama yang sebenarnya dilakukan oleh algoritma? Kami telah mengembangkan skema propagasi balik untuk kesalahan dari output. Apakah mungkin untuk melangkah lebih jauh, mendapatkan ide yang lebih intuitif tentang apa yang terjadi selama penggandaan vektor dan matriks ini? Teka-teki kedua adalah bagaimana orang bisa mendeteksi propagasi balik? Itu adalah satu hal untuk mengikuti langkah-langkah algoritma atau bukti operasinya. Tetapi ini tidak berarti bahwa Anda memahami masalah dengan sangat baik sehingga Anda dapat menemukan algoritma ini. Apakah ada garis penalaran yang masuk akal yang dapat mengarahkan kita pada penemuan algoritma backpropagation? Di bagian ini, saya akan membahas kedua teka-teki.
Untuk meningkatkan pemahaman tentang operasi algoritma, bayangkan bahwa kami membuat perubahan kecil smallw
l jk dengan bobot tertentu w
l jk :

Perubahan berat ini akan menyebabkan perubahan aktivasi output dari neuron yang sesuai:

Ini akan menyebabkan perubahan dalam semua aktivasi lapisan berikutnya:

Perubahan ini akan menyebabkan perubahan di lapisan berikutnya, dan seterusnya, hingga yang terakhir, dan kemudian ke perubahan fungsi biaya:

Perubahan ΔC terkait dengan perubahan Δw
l jk oleh persamaan
DeltaC approx frac partialC partialwljk Deltawljk tag47
Oleh karena itu pendekatan yang mungkin untuk menghitung ∂C / ∂w
l jk adalah dengan hati-hati memonitor penyebaran perubahan kecil
wljk , yang mengarah ke perubahan kecil dalam C. Jika kita dapat melakukan ini, dengan hati-hati menyatakan sepanjang jalan segala sesuatu dalam jumlah yang mudah untuk dihitung , maka kita dapat menghitung ∂C / ∂w
l jk .
Ayo kita coba. Perubahan Δw
l jk menyebabkan sedikit perubahan Δa
l j dalam aktivasi neuron pada lapisan l. Perubahan ini diatur.
Deltaalj approx frac partialalj partialwljk Deltawljk tag48
Perubahan aktivasi Δa
l j mengarah ke perubahan di semua aktivasi lapisan berikutnya, (l + 1). Kami hanya akan fokus pada salah satu dari aktivasi yang diubah ini, misalnya,
l + 1 q ,

Ini akan menghasilkan perubahan berikut:
Deltaal+1q approx frac partialal+1q partialalj Deltaalj tag49
Mengganti persamaan (48), kita memperoleh:
Deltaal+1q approx frac partialal+1q partialalj frac partialalj partialwljk Deltawljk tag50
Tentu saja, perubahan Δa
l + 1 q juga akan mengubah aktivasi di lapisan berikutnya. Kita bahkan dapat membayangkan jalur di seluruh jaringan dari w
l jk ke C, di mana setiap perubahan dalam aktivasi mengarah ke perubahan dalam aktivasi berikutnya, dan, akhirnya, ke perubahan dalam biaya pada output. Jika path melewati aktivasi a
l j , a
l + 1 q , ..., a
L - 1 n , a
L m , maka ekspresi terakhir akan menjadi
DeltaC approx frac partialC partialaLm frac partialaLm partialaL−1n frac partialaL−1n partialaL−2p ldots frac partialal+1q partialalj frac partialalj partialwljk Deltawljk tag51
Yaitu, kita memilih anggota dari bentuk ∂a / ∂a untuk setiap neuron berikutnya yang kita lewati, serta untuk istilah ∂C / ∂a Lm di akhir. Ini adalah representasi perubahan C karena perubahan aktivasi pada jalur khusus ini melalui jaringan. Tentu saja, ada banyak cara di mana perubahan dalam waktu dapat mempengaruhi dan memengaruhi biaya, dan kami hanya mempertimbangkan satu di antaranya. Untuk menghitung perubahan total dalam C, masuk akal untuk menganggap bahwa kita harus merangkum semua jalur yang mungkin dari bobot ke biaya akhir:
DeltaC approx summnp ldotsq frac partialC partialaLm frac partialaLm partialaL−1n frac partialaL−1n partialaL−2p ldots frac partialal+1q partialalj frac partialalj partialwljk Deltawljk tag52
di mana kami menyimpulkan semua pilihan yang mungkin untuk neuron perantara di sepanjang jalan. Membandingkan ini dengan (47), kita melihat bahwa:
frac partialC partialwljk= summnp ldotsq frac partialC partialaLm frac partialaLm partialaL−1n frac partialaL−1n partialaL−2p ldots frac partialal+1q partialalj frac partialalj partialwljk. tag53
Persamaan (53) terlihat rumit. Namun, itu memang memiliki interpretasi intuitif yang bagus. Kami menghitung perubahan C sehubungan dengan bobot jaringan. Ini memberitahu kita bahwa setiap tepi antara dua neuron jaringan dikaitkan dengan faktor rasio, yang hanya merupakan turunan parsial dari aktivasi satu neuron sehubungan dengan aktivasi neuron lain. Untuk iga dari bobot pertama ke neuron pertama, faktor rasio adalah la
l j / ∂w
l jk . Koefisien rasio untuk jalur hanyalah produk dari koefisien di sepanjang jalur. Dan total koefisien perubahan ∂C / ∂w
l jk adalah jumlah dari koefisien dalam segala hal dari bobot awal hingga biaya akhir. Prosedur ini ditunjukkan di bawah ini untuk satu jalur:

Sejauh ini, kami telah memberikan argumen heuristik, cara untuk mewakili apa yang terjadi ketika bobot jaringan berubah. Biarkan saya menguraikan cara berpikir lebih lanjut tentang topik ini untuk pengembangan argumen ini. Pertama, kita dapat menurunkan ekspresi yang tepat untuk semua turunan parsial individu dalam persamaan (53). Ini mudah dilakukan dengan menggunakan aljabar sederhana. Setelah itu, Anda dapat mencoba memahami cara menuliskan semua jumlah dengan indeks dalam bentuk produk matriks. Ini ternyata menjadi tugas yang membosankan yang membutuhkan kesabaran, tetapi bukan sesuatu yang luar biasa. Setelah semua ini dan penyederhanaan maksimum, Anda akan melihat bahwa algoritma backpropagation yang sama persis diperoleh! Oleh karena itu, algoritma backpropagation dapat dibayangkan sebagai cara menghitung jumlah koefisien untuk semua jalur. Atau, untuk merumuskan kembali, algoritma backpropagation adalah cara yang rumit untuk melacak perubahan kecil dalam bobot (dan offset) ketika mereka merambat di jaringan, mencapai output, dan memengaruhi biaya.
Di sini saya tidak akan melakukan semua ini. Bisnis ini tidak menarik, membutuhkan studi detail yang cermat. Jika Anda siap untuk ini, Anda mungkin ingin melakukan ini. Jika tidak, saya harap pemikiran seperti itu akan memberi Anda beberapa gagasan mengenai tujuan backpropagation.
Bagaimana dengan teka-teki lain - bagaimana bisa propagasi balik ditemukan? Bahkan, jika Anda mengikuti jalan yang telah saya uraikan, Anda akan menerima bukti propagasi balik. Sayangnya, buktinya akan lebih panjang dan lebih rumit dari apa yang saya jelaskan sebelumnya. Jadi, bagaimana bukti singkat (tetapi bahkan lebih misterius) itu ditemukan? Jika Anda menuliskan semua detail bukti panjang, Anda akan segera melihat beberapa penyederhanaan yang jelas. Anda menerapkan penyederhanaan, mendapatkan bukti yang lebih sederhana, menuliskannya. Dan kemudian Anda menemukan beberapa penyederhanaan yang jelas. Dan Anda mengulangi prosesnya. Setelah beberapa kali pengulangan, bukti yang kita lihat sebelumnya akan pendek, tapi agak tidak bisa dipahami, karena semua tonggak sejarah telah dihapus dari itu! Tentu saja, saya sarankan Anda mengambil kata saya untuk itu, tetapi sebenarnya tidak ada misteri tentang asal-usul buktinya. Hanya banyak kerja keras untuk menyederhanakan bukti yang saya jelaskan di bagian ini.
Namun, ada satu trik pintar dalam proses ini. Dalam persamaan (53), variabel antara adalah aktivasi tipe a
l + 1 q . Caranya adalah dengan beralih menggunakan input tertimbang, seperti z
l + 1 q , sebagai variabel perantara. Jika Anda tidak menggunakan ini dan terus menggunakan aktivasi, bukti yang diperoleh akan sedikit lebih rumit daripada yang diberikan sebelumnya dalam bab ini.