Contoh langkah demi langkah diferensiasi otomatis mode terbalik

27

Tidak yakin apakah pertanyaan ini ada di sini, tetapi terkait erat dengan metode gradien dalam pengoptimalan, yang tampaknya menjadi topik di sini. Bagaimanapun, jangan ragu untuk bermigrasi jika Anda pikir beberapa komunitas lain memiliki keahlian yang lebih baik dalam topik ini.

Singkatnya, saya mencari contoh selangkah demi selangkah dari diferensiasi otomatis mode terbalik . Tidak banyak literatur tentang topik di luar sana dan implementasi yang ada (seperti yang ada di TensorFlow ) sulit untuk dipahami tanpa mengetahui teori di baliknya. Jadi saya akan sangat berterima kasih jika seseorang dapat menunjukkan secara rinci apa yang kami lewati , bagaimana kami memprosesnya dan apa yang kami ambil dari grafik komputasi.

Beberapa pertanyaan yang paling sulit saya hadapi:

  • biji - mengapa kita membutuhkannya?
  • membalikkan aturan diferensiasi - Saya tahu bagaimana membuat diferensiasi maju, tetapi bagaimana kita mundur? Misalnya dalam contoh dari bagian ini , bagaimana kita tahu bahwa ?w2¯=w3¯w1
  • apakah kita hanya bekerja dengan simbol atau melewati nilai aktual ? Misalnya dalam contoh yang sama , apakah dan simbol atau nilai?¯ w iwsayawsaya¯
teman
sumber
"Pembelajaran Mesin Langsung dengan Scikit-Learn & TensorFlow" Lampiran D memberikan pendapat yang sangat bagus menurut saya. Saya merekomendasikannya.
Agustin Barrachina

Jawaban:

37

Katakanlah kita memiliki ekspresi dan ingin mencari turunan dan . Reverse-mode AD membagi tugas ini menjadi 2 bagian, yaitu, meneruskan dan membalikkan pass.z=x1x2+sin(x1)dzdx1dzdx2

Maju terus

Pertama, kami menguraikan ekspresi kompleks kami menjadi satu set yang primitif, yaitu ekspresi yang terdiri dari paling banyak pemanggilan fungsi tunggal. Perhatikan bahwa saya juga mengganti nama variabel input dan output untuk konsistensi, meskipun itu tidak perlu:

w1=x1
w2=x2
w3=w1w2
w4=sin(w1)
w5=w3+w4
z=w5

Keuntungan dari representasi ini adalah bahwa aturan diferensiasi untuk setiap ekspresi yang terpisah sudah diketahui. Sebagai contoh, kita tahu bahwa turunan dari adalah , dan karenanya . Kami akan menggunakan fakta ini secara terbalik di bawah ini.sincosdw4dw1=cos(w1)

Pada dasarnya, umpan maju terdiri dari mengevaluasi setiap ekspresi ini dan menyimpan hasilnya. Katakan, input kami adalah: dan . Maka kita memiliki:x1=2x2=3

w1=x1=2
w2=x2=3
w3=w1w2=6
w4=sin(w1) =0.9
w5=w3+w4=6.9
z=w5=6.9

Reverse pass

Ini adalah keajaiban dimulai, dan itu dimulai dengan aturan rantai . Dalam bentuk dasarnya, aturan rantai menyatakan bahwa jika Anda memiliki variabel yang bergantung pada yang, pada gilirannya, tergantung pada , maka:t(u(v))uv

dtdv=dtdududv

atau, jika bergantung pada melalui beberapa jalur / variabel , mis:tvui

u1=f(v)
u2=g(v)
t=h(u1,u2)

lalu (lihat buktinya di sini ):

dtdv=idtdusayadkamusayadv

Dalam hal grafik ekspresi, jika kita memiliki simpul akhir dan simpul input , dan jalur dari ke melewati simpul perantara (yaitu mana ), kita dapat menemukan turunannya sebagaizwsayazwsayawhalz=g(wp)wp=f(wi)dzdwi

dzdwi=pparents(i)dzdwhaldwhaldwsaya

Dengan kata lain, untuk menghitung turunan dari variabel keluaran wrt variabel antara atau input , kita hanya perlu mengetahui turunan dari orang tuanya dan rumus untuk menghitung turunan dari ekspresi primitif .zwsayawhal=f(wsaya)

Reverse pass dimulai pada bagian akhir (yaitu ) dan menyebar mundur ke semua dependensi. Di sini kita punya (ekspresi untuk "seed"):dzdz

dzdz=1

Itu dapat dibaca sebagai "perubahan dalam menghasilkan perubahan yang persis sama dalam ", yang cukup jelas.zz

Maka kita tahu bahwa dan sebagainya:z=w5

dzdw5=1

w5 secara linear tergantung pada dan , jadi dan . Menggunakan aturan rantai kami menemukan:w3w4dw5dw3=1dw5dw4=1

dzdw3=dzdw5dw5dw3=1×1=1
dzdw4=dzdw5dw5dw4=1×1=1

Dari definisi dan aturan turunan parsial, kami menemukan bahwa . Demikian:w3=w1w2dw3dw2=w1

dzdw2=dzdw3dw3dw2=1×w1=w1

Yang, seperti yang sudah kita ketahui dari umpan maju, adalah:

dzdw2=w1=2

Akhirnya, berkontribusi ke melalui dan . Sekali lagi, dari aturan turunan parsial kita tahu bahwa dan . Demikian:w1zw3w4dw3dw1=w2dw4dw1=cos(w1)

dzdw1=dzdw3dw3dw1+dzdw4dw4dw1=w2+cos(w1)

Dan lagi, mengingat input yang diketahui, kita dapat menghitungnya:

dzdw1=w2+cos(w1)=3+cos(2) =2.58

Karena dan hanyalah alias untuk dan , kami mendapatkan jawaban kami:w1w2x1x2

dzdx1=2.58
dzdx2=2

Dan itu dia!


Deskripsi ini hanya menyangkut input skalar, yaitu angka, tetapi sebenarnya itu juga dapat diterapkan pada array multidimensi seperti vektor dan matriks. Dua hal yang harus diingat ketika membedakan ekspresi dengan objek-objek tersebut:

  1. Derivatif mungkin memiliki dimensi yang jauh lebih tinggi daripada input atau output, misalnya turunan dari vektor wrt vektor adalah matriks dan turunan dari matriks wrt adalah array 4 dimensi (kadang-kadang disebut sebagai tensor). Dalam banyak kasus turunan seperti itu sangat jarang.
  2. Setiap komponen dalam larik keluaran adalah fungsi independen dari 1 atau lebih komponen larik masukan. Misalkan jika dan keduanya dan adalah vektor, tidak pernah bergantung pada , tetapi hanya pada subset dari . Secara khusus, ini berarti menemukan turunan bermuara pada pelacakan bagaimana bergantung pada .y=f(x)xyysayayjxkdysayadxjysayaxj

Kekuatan diferensiasi otomatis adalah bahwa ia dapat menangani struktur rumit dari bahasa pemrograman seperti kondisi dan loop. Namun, jika semua yang Anda butuhkan adalah ekspresi aljabar dan Anda memiliki kerangka kerja yang cukup baik untuk bekerja dengan representasi simbolik, dimungkinkan untuk membangun ekspresi simbolik sepenuhnya. Pada kenyataannya, dalam contoh ini kita dapat menghasilkan ekspresi dan menghitung turunan ini untuk input apa pun yang kita inginkan.dzdw1=w2+cos(w1)=x2+cos(x1)

teman
sumber
1
Pertanyaan / jawaban yang sangat berguna. Terima kasih. Hanya kritik kecil: Anda tampaknya bergerak di atas struktur pohon tanpa menjelaskan (saat itulah Anda mulai berbicara tentang orang tua, dll.)
MadHatter
1
Juga tidak ada salahnya menjelaskan mengapa kita membutuhkan benih.
MadHatter
dzdz=1
Terima kasih! Saya perhatikan ketika Anda harus menetapkan lebih dari satu "seed", umumnya seseorang memilih 1 dan 0. Saya ingin tahu mengapa. Maksud saya, orang mengambil "hasil bagi" dari wrt diferensial itu sendiri, jadi "1" setidaknya secara intuitif dibenarkan .. Tapi bagaimana dengan 0? Dan bagaimana jika seseorang harus memilih lebih dari 2 biji?
MadHatter
1
Sejauh yang saya mengerti, lebih dari satu seed hanya digunakan dalam mode forward-AD. Dalam hal ini Anda mengatur seed ke 1 untuk variabel input yang ingin Anda bedakan sehubungan dengan dan mengatur seed ke 0 untuk semua variabel input lainnya sehingga mereka tidak berkontribusi pada nilai output. Dalam mode terbalik, Anda mengatur seed ke variabel output , dan Anda biasanya hanya memiliki satu variabel output. Saya kira, Anda dapat membangun pipa AD mode balik dengan beberapa variabel output dan mengatur semuanya tetapi satu ke 0 untuk mendapatkan efek yang sama seperti dalam mode maju, tapi saya belum pernah menyelidiki opsi ini.
berteman