Ha, siz backpropni tushunishingiz kerak

Biz Stenfordda CS231n (Deep Learning class) ni taklif qilganimizda, biz dasturlash topshiriqlarini qasddan eng past darajadagi ortga surish bilan bog'liq bo'lgan aniq hisob-kitoblarni kiritish uchun ishlab chiqdik. Talabalar har bir qatlamning oldinga va orqaga o'tishini xom nubusda bajarishlari kerak edi. Shubhasiz, ba'zi o'quvchilar sinf xabar taxtalarida shikoyat qilishdi:

"TensorFlow kabi haqiqiy dunyoda ramkalar ularni avtomatik ravishda hisoblab chiqqanda, biz nima uchun orqaga o'tib ketishni yozishimiz kerak?"

Aftidan, bu juda aqlga sig'adigan narsa - agar siz dars tugaganidan keyin orqaga o'tib ketishni yozmasangiz, nega ularni yozishni mashq qilasiz? Biz shunchaki o'yin-kulgimiz uchun talabalarni azoblayapmizmi? Ba'zi bir oson javoblar "qalpoq ostidagi narsalarni intellektual qiziqish sifatida bilish kerak" yoki ehtimol "keyinroq algoritmda yaxshilanishni xohlashingiz mumkin" qatorlari bo'yicha dalillarni keltirib chiqarishi mumkin, ammo ancha kuchli va amaliy dalillar mavjud. Men butun xabarni quyidagilarga bag'ishlamoqchi edim:

Backpropagation bilan bog'liq muammo shundaki, bu abstraktsiya.

Boshqacha qilib aytganda, o'quv jarayonini mavhumlashtirish tuzog'iga tushish juda oson - siz shunchaki o'zboshimchalik qatlamlarini bir joyga to'plashingiz mumkinligiga ishonasiz va zaxira o'pish sizning ma'lumotlaringizda "sehrli ishlashga" imkon beradi. Shunday qilib, bir nechta aniq misollarni ko'rib chiqaylik, bu erda asossiz bo'lmagan holatlar mavjud emas.

Ba'zi bir ko'z shakar shakli: oldinga o'tish (qora) va orqaga o'tish (qizil) bilan Batch Norm qatlamining hisoblash grafigi. (ushbu lavozimdan olingan)

Sigmasimon bezlarning yo'qolishi

Biz bu erda oson boshlayapmiz. Bir vaqtning o'zida to'liq bog'langan qatlamlarda sigmasimon (yoki tan) chiziqli bo'lmaganlardan foydalanish moda edi. Odamlarning qiyin tomoni, ular orqaga o'tish haqida o'ylamaguncha anglamasligi mumkin: agar siz og'irlikni boshlash yoki ma'lumotni qayta ishlash bilan qiynalsangiz, bu nomutanosibliklar "to'yingan" bo'lishi mumkin va umuman o'qishni to'xtatishi mumkin - sizning mashg'ulotingiz yo'q bo'lib ketadi va ketishdan bosh tortadi. pastga. Masalan, sigmasimon chiziqli bo'lmagan hisoblashlar bilan to'liq bog'langan qatlam (xom bo'r yordamida):

z = 1 / (1 + np.exp (-np.dot (W, x))) # oldinga o'tish
dx = np.dot (W.T, z * (1-z)) # orqaga o'tish: x uchun mahalliy gradient
dW = np.outer (z * (1-z), x) # orqaga o'tish: Vt uchun mahalliy gradient

Agar sizning vazningiz W matritsasi juda katta bo'lsa, matritsaning ko'payishi juda katta diapazonga ega bo'lishi mumkin (masalan, -400 dan 400 gacha bo'lgan raqamlar) va vektorning barcha chiqishlarini z deyarli ikkilikli bo'ladi: yo 1 yoki 0. Ammo. Agar shunday bo'lsa, sigmasimon chiziqli bo'lmagan mahalliy gradient bo'lgan z * (1-z) har ikki holatda ham nolga aylanadi ("yo'qoladi") va x va V uchun gradient nolga teng bo'ladi. Orqaga orqaga o'tishning qolgan qismi zanjir qoidasida ko'payish tufayli shu noldan chiqadi.

Sigmasimon yana bir noaniq qiziqarli fakt, uning mahalliy gradienti (z * (1-z)) z = 0,5 bo'lganida maksimal 0,25 ga etadi. Bu shuni anglatadiki, gradient signal har safar sigmasimon darvozadan oqib kelganda, uning kattaligi har doim chorakka (yoki undan ko'proq) kamayadi. Agar siz asosiy SGD-dan foydalansangiz, bu tarmoq poezdining pastki qatlamlarini yuqoriroqlaridan pastroq qiladi.

TLDR: agar siz o'z tarmog'ingizda sigmasimon yoki notekis chiziqlardan foydalansangiz va ortga surib qo'yishni tushunsangiz, bu harflarning boshlang'ich to'liq to'yinganligiga olib kelmasligiga ishonch hosil qilishingiz kerak. Ushbu CS231n ma'ruza videoida uzoqroq tushuntirishga qarang.

O'LISh HAQIDA

Yana bir qiziqarli bo'lmagan chiziq bu ReLU bo'lib, u neyronlarning ostidan nolga tushadi. ReLU-dan foydalanadigan to'liq ulangan qatlam uchun oldinga va orqaga o'tish pasayishiga quyidagilar kiradi:

z = np.maximum (0, np.dot (W, x)) # oldinga o'tish
dW = np.outer (z> 0, x) # orqaga o'tish: Vt uchun mahalliy gradient

Agar bir muncha vaqt tikilib qarasangiz, oldingi o'tish joyida neyron nolga tushib qolsa (ya'ni z = 0 bo'lsa, u “otmaydi”), unda uning og'irligi nol gradyanga ega bo'ladi. Bu "o'lik ReLU" deb nomlangan muammoga olib kelishi mumkin, agar ReLU neyroni, afsuski, u hech qachon yiqilmasligi uchun ishga tushirilsa yoki neyronning og'irliklari ushbu rejimga o'tishda katta yangilanish bilan yiqilib tushsa, unda bu neyron. butunlay o'lik holda qoladi. Bu miyaning doimiy, tiklanmaydigan shikastlanishi kabi. Ba'zan siz o'qitilgan tarmoq orqali butun mashg'ulotni yo'naltirishingiz va neyronlaringizning katta qismi (masalan, 40%) butun vaqt davomida nolga teng ekanligini topishingiz mumkin.

TLDR: Agar siz orqa mundarijani tushunsangiz va tarmog'ingizda YO'Q mavjud bo'lsa, siz har doim o'lik ReLU haqida asabiylashasiz. Bular neyronlardir, ular hech qachon sizning barcha mashg'ulotlaringizdagi biron bir misolni yoqmaydi va o'lik holda qoladi. Neyronlar, shuningdek, mashg'ulot paytida o'lishlari mumkin, odatda bu tajovuzkor o'rganish darajasining belgisi sifatida. CS231n ma'ruza videosida uzoqroq tushuntirishga qarang.

RNN-larda portlovchi gradientlar

Vanilya RNNlarida orqa miya qo'zg'alishining noo'rin ta'sirining yana bir yaxshi namunasi mavjud. Men slaydni CS231n-dan nusxa ko'chiraman, u soddalashtirilgan RNN-ga ega bo'lib, u hech qanday kiritish x-ni olmaydi va faqat yashirin holatdagi takrorlanishni hisoblaydi (kiritish x har doim nol bo'lishi mumkin):

Ushbu RNN T vaqtli qadamlar uchun ro'yxatga olinmagan. Orqaga o'tish pog'onasi nima qilayotganiga nazar tashlasangiz, barcha yashirin holatlar orqali vaqt o'tishi bilan gradient signal har doim bir xil matritsa bilan ko'payayotganini ko'rasiz (qaytarilish matritsasi - Whh) va chiziqsiz orqa orqa bilan kesishgan.

Bir raqamni olib, uni boshqa b raqamiga ko'paytirgandan so'ng nima sodir bo'ladi (masalan, a * b * b * b * b * b * b ...)? Ushbu ketma-ketlik, agar | b | bo'lsa yoki nolga tushadi <1, yoki | b |> 1 bo'lganda cheksizlikka portlaydi. Xuddi shu narsa RNNning orqaga o'tish joyida sodir bo'ladi, b - bu matritsa va shunchaki raqam emas, shuning uchun biz uning eng katta eigenval qiymati haqida o'ylashimiz kerak.

TLDR: Agar siz orqa mundarijani tushunsangiz va siz RNN-dan foydalanayotgan bo'lsangiz, siz gradient qirqish kerakligini bilmayapsiz yoki LSTM-dan foydalanishni afzal ko'rasiz. Ushbu CS231n ma'ruza videosida uzoqroq tushuntirishga qarang.

Yovvoyi tabiatda ko'rinadigan: DQN kesish

Yana bir narsani ko'rib chiqaylik - aslida ushbu xabarni ilhomlantirgan. Kecha men TensorFlow-da Deep Q Learning dasturini ko'rib chiqayotgan edim (boshqalar Q [:, a] sonini ekvivalenti hisoblash bilan qanday ishlashini ko'rish uchun, bu erda a butun son vektor - bu ahamiyatsiz operatsiya TFda qo'llab-quvvatlanmaydi). Qanday bo'lmasin, men "dqn tensorflow" ni qidirdim, birinchi havolani bosdim va asosiy kodni topdim. Mana parcha:

Agar siz DQN bilan tanish bo'lsangiz, target_q_t borligini ko'rishingiz mumkin, u shunchaki [mukofot * \ gamma \ argmax_a Q (s ', a)] va keyin q_acted mavjud, ya'ni Q (s, a) amalga oshirilgan harakatlar. Bu erda mualliflar ikkalasini o'zgaruvchan deltalarga ajratadilar, ular keyin tf.reduce_mean (tf.square ()) yordamida L2 yo'qotilishi bilan 295-qatorda kamaytirishni xohlashadi. Hozircha hammasi yaxshi.

Muammo 291-qatorda. Mualliflar tashqi sotuvchilardan ishonchli bo'lishga harakat qilmoqdalar, shuning uchun agar delta juda katta bo'lsa, uni tf.clip_by_value bilan yopishtiradilar. Bu puxta o'ylangan va oldinga o'tish paslari nuqtai nazaridan sezgir ko'rinadi, ammo agar siz oldingi paslar haqida o'ylasangiz, katta xato paydo bo'ladi.

Clip_by_value funktsiyasi min_delta-dan max_delta oralig'idan tashqarida nolga teng mahalliy gradyanga ega, shuning uchun delta min / max_delta dan yuqori bo'lsa, orqa naychada gradient aniq nolga aylanadi. Mualliflar qo'shimcha Qattiqlik uchun gradientni klipga tushirishga harakat qilganda, xom Q deltasini qirqishadi. Bu holda to'g'ri ish qilish bu tf.square o'rniga Huber yo'qotishidan foydalanish:

def clipped_error (x):
  return tf.select (tf.abs (x) <1.0,
                   0,5 * tf.square (x),
                   tf.abs (x) - 0.5) # shart, to'g'ri, noto'g'ri

TensorFlow-da bu juda qo'poldir, chunki biz gradientni agar u pol qiymatidan yuqori bo'lsa, uni qisib qo'yishni istaymiz, lekin gradient bilan bevosita aralasha olmasligimiz sababli biz buni Huber yo'qotilishini aniqlashning yaxlit usulida bajarishimiz kerak. . Torchada bu ancha sodda bo'lar edi.

Men DQN repo-da muammoni topshirdim va bu tezda hal qilindi.

Xulosa

Backpropagatsiya - bu oqayotgan abstraktsiya; bu arzimas oqibatlarga olib keladigan kreditni berish sxemasi. Agar siz "TensorFlow avtomatik ravishda tarmoqlarimni o'rganishga majbur qiladi" degani uchun, u kaput ostida qanday ishlashini e'tiborsiz qoldirishga harakat qilsangiz, unda mavjud bo'lgan xavf bilan kurashishga tayyor bo'lmaysiz va neyron tarmoqlarini tuzishda va disk raskadrovka qilishda samarasiz bo'lasiz.

Yaxshi xabar shundaki, agar to'g'ri taqdim etilgan bo'lsa, orqa miyadagi narsalarni tushunish qiyin emas. Men bu mavzuda nisbatan kuchli his-tuyg'ularga egaman, chunki menimcha, u erda 95% backpropagation materiallari noto'g'ri va sahifalarni mexanik matematikaga to'ldiradi. Buning o'rniga men sezgirlikni ta'kidlaydigan orqa miya haqida CS231n ma'ruzasini tavsiya qilaman (uyatsiz o'zini o'zi reklama qilish uchun tayyor). Agar bo'sh vaqtingizni bonus sifatida sarflasangiz, CS231n topshiriqlari orqali ishlang, bu sizga qo'lda backprop yozishga imkon beradi va tushunchangizni mustahkamlashga yordam beradi.

Hozir shu! Umid qilamanki, siz oldinga o'tishda orqaga qaytish haqida ko'proq shubhalanasiz va orqadagi pas qanday amalga oshirilayotgani haqida yaxshilab o'ylab ko'rasiz. Bundan tashqari, men ushbu xabarni (beixtiyor!) Bir nechta CS231n reklamalariga aylantirganligini bilaman. Buning uchun uzr so'rayman :)