ตัวอย่างทีละขั้นตอนของการสร้างความแตกต่างโดยอัตโนมัติในโหมดย้อนกลับ


27

ไม่แน่ใจว่าคำถามนี้อยู่ที่นี่หรือไม่ แต่เป็นเรื่องที่เกี่ยวข้องกับวิธีการไล่ระดับสีในการปรับให้เหมาะสมซึ่งดูเหมือนจะอยู่ในหัวข้อที่นี่ อย่างไรก็ตามคุณสามารถโยกย้ายได้ถ้าคุณคิดว่าชุมชนอื่นมีความเชี่ยวชาญในหัวข้อนี้มากกว่า

ในระยะสั้นฉันกำลังมองหาตัวอย่างขั้นตอนโดยขั้นตอนของโหมดกลับแตกต่างอัตโนมัติ มีวรรณกรรมไม่มากในหัวข้อที่มีและการใช้งานที่มีอยู่ (เช่นใน TensorFlow ) ยากที่จะเข้าใจโดยไม่ทราบทฤษฎีที่อยู่เบื้องหลัง ดังนั้นฉันจะขอบคุณมากถ้ามีคนสามารถแสดงรายละเอียดสิ่งที่เราส่งผ่านวิธีที่เราดำเนินการและสิ่งที่เรานำออกจากกราฟการคำนวณ

สองคำถามที่ฉันมีปัญหากับ:

  • เมล็ด - ทำไมเราต้องการพวกเขาทั้งหมด
  • ย้อนกลับกฎความแตกต่าง - ฉันรู้วิธีสร้างความแตกต่างไปข้างหน้า แต่เราจะย้อนกลับได้อย่างไร เช่นในตัวอย่างจากส่วนนี้อย่างไรเรารู้ว่าw2¯=w3¯w1 ?
  • เราจะทำงานกับสัญลักษณ์เท่านั้นหรือส่งผ่านค่าจริงหรือไม่ เช่นในตัวอย่างเดียวกันเป็นwiและwi¯สัญลักษณ์หรือค่า?

"การเรียนรู้ของเครื่องบนมือกับ Scikit-Learn & TensorFlow" ภาคผนวก D ให้คำอธิบายที่ดีมากในความคิดของฉัน ฉันแนะนำมัน
Agustin Barrachina

คำตอบ:


37

สมมุติว่าเรามีนิพจน์z=x1x2+sin(x1)และต้องการหาอนุพันธ์dzdx1และdzdx2 2 โฆษณาโหมดย้อนกลับแบ่งงานนี้ออกเป็น 2 ส่วนคือส่งต่อและย้อนกลับ

ส่งต่อ

อันดับแรกเราแยกการแสดงออกที่ซับซ้อนของเราออกเป็นชุดของการเขียนแบบดั้งเดิมเช่นการแสดงออกที่ประกอบด้วยการเรียกใช้ฟังก์ชันเดียว โปรดทราบว่าฉันยังเปลี่ยนชื่อตัวแปรอินพุตและเอาต์พุตเพื่อความสอดคล้องแม้ว่ามันไม่จำเป็น:

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

ข้อได้เปรียบของการเป็นตัวแทนนี้ก็คือการรู้จักกฎการสร้างความแตกต่างสำหรับแต่ละนิพจน์แยกกันอยู่แล้ว ตัวอย่างเช่นเรารู้ว่าที่มาของsinคือcosและอื่น ๆdw4dw1=cos(w1)) เราจะใช้ข้อเท็จจริงนี้ในการส่งผ่านย้อนกลับด้านล่าง

โดยพื้นฐานแล้วฟอร์เวิร์ดพาสประกอบด้วยการประเมินแต่ละนิพจน์และบันทึกผลลัพธ์ กล่าวว่าปัจจัยการผลิตของเรา: x1=2และx2=3 3 จากนั้นเรามี:

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

ย้อนกลับ

นี่คือการเริ่มต้นเป็นความมหัศจรรย์และมันเริ่มต้นด้วยกฎลูกโซ่ ในรูปแบบพื้นฐานกฎลูกโซ่ระบุว่าหากคุณมีตัวแปรt(u(v))ซึ่งขึ้นอยู่กับuซึ่งในทางกลับกันขึ้นอยู่กับvดังนั้น:

dtdv=dtdududv

หรือถ้าtขึ้นอยู่กับvผ่านหลายเส้นทาง / ตัวแปรuiเช่น:

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

จากนั้น (ดูข้อพิสูจน์ที่นี่ ):

dtdv=idtduiduidv

ในแง่ของกราฟนิพจน์หากเรามีโหนดสุดท้ายzและโหนดอินพุตwiและพา ธ จากzถึงwiผ่านโหนดกลางwp (เช่นz=g(wp)โดยที่wp=f(wi) ) เราสามารถหาอนุพันธ์dzdwiเป็น

dzdwi=pparents(i)dzdwpdwpdwi

ในคำอื่น ๆ ในการคำนวณอนุพันธ์ของตัวแปรเอาท์พุทz WRT ตัวแปรกลางหรือป้อนข้อมูลใด ๆwiเราจำเป็นต้องรู้อนุพันธ์ของพ่อแม่และสูตรการคำนวณที่มาของการแสดงออกดั้งเดิมwp=f(wi) )

Reverse pass เริ่มที่จุดสิ้นสุด (เช่นdzdz) and propagates backward to all dependencies. Here we have (expression for "seed"):

dzdz=1

That may be read as "change in z results in exactly the same change in z", which is quite obvious.

Then we know that z=w5 and so:

dzdw5=1

w5 linearly depends on w3 and w4, so dw5dw3=1 and dw5dw4=1. Using the chain rule we find:

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

From definition w3=w1w2 and rules of partial derivatives, we find that dw3dw2=w1. Thus:

dzdw2=dzdw3dw3dw2=1×w1=w1

Which, as we already know from forward pass, is:

dzdw2=w1=2

Finally, w1 contributes to z via w3 and w4. Once again, from the rules of partial derivatives we know that dw3dw1=w2 and dw4dw1=cos(w1). Thus:

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

And again, given known inputs, we can calculate it:

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

Since w1 and w2 are just aliases for x1 and x2, we get our answer:

dzdx1=2.58
dzdx2=2

And that's it!


This description concerns only scalar inputs, i.e. numbers, but in fact it can also be applied to multidimensional arrays such as vectors and matrices. Two things that one should keep in mind when differentiating expressions with such objects:

  1. Derivatives may have much higher dimensionality than inputs or output, e.g. derivative of vector w.r.t. vector is a matrix and derivative of matrix w.r.t. matrix is a 4-dimensional array (sometimes referred to as a tensor). In many cases such derivatives are very sparse.
  2. Each component in output array is an independent function of 1 or more components of input array(s). E.g. if y=f(x) and both x and y are vectors, yi never depends on yj, but only on subset of xk. In particular, this means that finding derivative dyidxj boils down to tracking how yi depends on xj.

The power of automatic differentiation is that it can deal with complicated structures from programming languages like conditions and loops. However, if all you need is algebraic expressions and you have good enough framework to work with symbolic representations, it's possible to construct fully symbolic expressions. In fact, in this example we could produce expression dzdw1=w2+cos(w1)=x2+cos(x1) and calculate this derivative for whatever inputs we want.


1
Very useful question/answer. Thanks. Just a litte criticism: you seem to move on a tree structure without explaining (that's when you start talking about parents, etc..)
MadHatter

1
Also it won't hurt clarifying why we need seeds.
MadHatter

@MadHatter thanks for the comment. I tried to rephrase a couple of paragraphs (these that refer to parents) to emphasize a graph structure. I also added "seed" to the text, although this name itself may be misleading in my opinion: in AD seed is always a fixed expression - dzdz=1, not something you can choose or generate.
ffriend

Thanks! I noticed when you have to set more than one "seed", generally one chooses 1 and 0. I'd like to know why. I mean, one takes the "quotient" of a differential w.r.t. itself, so "1" is at least intuitively justified.. But what about 0? And what if one has to pick more than 2 seeds?
MadHatter

1
As far as I understand, more than one seed is used only in forward-mode AD. In this case you set the seed to 1 for an input variable you want to differentiate with respect to and set the seed to 0 for all the other input variables so that they don't contribute to the output value. In reverse-mode you set the seed to an output variable, and you normally have only one output variable. I guess, you can construct reverse-mode AD pipeline with several output variables and set all of them but one to 0 to get the same effect as in forward mode, but I have never investigated this option.
ffriend
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.