<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 附錄 D、自動微分 > 譯者:[@rickllyxu](https://github.com/rickllyxu) 這個附錄解釋了 TensorFlow 的自動微分功能是如何工作的,以及它與其他解決方案的對比。 假定你定義了函數 ![f(x, y) = x^2y + y + 2](https://img.kancloud.cn/84/f5/84f51a1c782f49b88f5f584262ed7d40_166x20.gif),需要得到它的偏導數 ![\frac{\partial f}{\partial x}](https://img.kancloud.cn/05/c1/05c1c279cff28e047168dd0298019c9d_22x39.gif) 和 ![\frac{\partial f}{\partial y}](https://img.kancloud.cn/d6/07/d607095498c0f94be18359c08e55d5cf_22x42.gif),以用于梯度下降或者其他優化算法。你的可選方案有手動微分法,符號微分法,數值微分法,前向自動微分,和反向自動微分。TensorFlow 實現的反向自動微分法。我們來看看每種方案。 ## 手動微分法 第一個方法是拿起一直筆和一張紙,使用你的代數知識去手動的求偏導數。對于已定義的函數,求它的偏導并不太困難。你需要使用如下 5 條規則: - 常數的導數為 0。 - ![\lambda x](https://img.kancloud.cn/bd/56/bd56d5c72306dc7ea94034f125e6f7a9_20x12.gif) 的導數為 ![\lambda](https://img.kancloud.cn/99/d3/99d394e7d0b74248114405067e0ffd51_10x12.jpg),![\lambda](https://img.kancloud.cn/99/d3/99d394e7d0b74248114405067e0ffd51_10x12.jpg) 為常數。 - ![x^{\lambda}](https://img.kancloud.cn/a9/f7/a9f7350469db3692d5e1fe7e456dc73f_18x16.gif) 的導數是 ![\lambda x^{\lambda - 1}](https://img.kancloud.cn/e4/c3/e4c3387d4b2f9262ef1fa8a82e7014d8_44x16.gif) - 函數的和的導數,等于函數的導數的和 - ![\lambda](https://img.kancloud.cn/99/d3/99d394e7d0b74248114405067e0ffd51_10x12.jpg) 乘以函數,再求導,等于 ![\lambda](https://img.kancloud.cn/99/d3/99d394e7d0b74248114405067e0ffd51_10x12.jpg) 乘以函數的導數 從上述這些規則,可得到公式 D-1。 ![公式D-1](https://img.kancloud.cn/7f/d4/7fd4c1aa6cd2a83ebd8e89ffaeaf1949_538x217.png) 這個種方法應用于更復雜函數時將變得非常羅嗦,并且有可能出錯。好消息是,像剛才我們做的求數學式子的偏導數可以被自動化,通過一個稱為符號微分的過程。 ## 符號微分 圖 D-1 展示了符號微分是如何運行在相當簡單的函數上的,![g(x,y) = 5 + xy](https://img.kancloud.cn/28/62/28622fbd30b4f7340053724088d3eb65_125x18.gif)。該函數的計算圖如圖的左邊所示。通過符號微分,我們可得到圖的右部分,它代表了 ![\frac{\partial g}{\partial x} = 0 + (0 \times x + y \times 1) = y](https://img.kancloud.cn/9c/ca/9cca26166b0faea7e200d6be62a6e18d_229x39.gif),相似地也可得到關于`y`的導數。 ![D-1](https://img.kancloud.cn/9b/fb/9bfb691e57ff0f864cb36823a917b144_938x571.png) 概算法先獲得葉子節點的偏導數。常數 5 返回常數 0,因為常數的導數總是 0。變量`x`返回常數 1,變量`y`返回常數 0,因為 ![\frac{\partial y}{\partial x} = 0](https://img.kancloud.cn/14/a0/14a007db0bb8de434f01267c385534c7_55x39.gif)(如果我們找關于`y`的偏導數,那它將反過來)。 現在我們移動到計算圖的相乘節點處,代數告訴我們,`u`和`v`相乘后的導數為 ![\frac{\partial (u \times v)}{\partial x} = \frac{\partial v}{\partial x} \times u + \frac{\partial u}{\partial x} \times v ](https://img.kancloud.cn/b8/de/b8de96a430b50464a6f5297af3224ef9_226x40.gif)。因此我們可以構造有圖中大的部分,代表`0 × x + y × 1`。 最后我們往上走到計算圖的相加節點處,正如 5 條規則里提到的,和的導數等于導數的和。所以我們只需要創建一個相加節點,連接我們已經計算出來的部分。我們可以得到正確的偏導數,即:![\frac{\partial g}{\partial x} = 0 + (0 \times x + y \times 1) ](https://img.kancloud.cn/10/4f/104fc8550f0e58f8a23d70bcc39384e3_195x39.gif)。 然而,這個過程可簡化。對該圖應用一些微不足道的剪枝步驟,可以去掉所有不必要的操作,然后我們可以得到一個小得多的只有一個節點的偏導計算圖:![\frac{\partial g}{\partial x} = y](https://img.kancloud.cn/64/fa/64fa1dab8099d82d3c4b1dc3cc7888d6_55x39.gif)。 在這個例子里,簡化操作是相當簡單的,但對更復雜的函數來說,符號微分會產生一個巨大的計算圖,該圖可能很難去簡化,以導致次優的性能。更重要的是,符號微分不能處理由任意代碼定義的函數,例如,如下已在第 9 章討論過的函數: ```python def my_func(a, b): z = 0 for i in range(100): z = a * np.cos(z + i) + z * np.sin(b - i) return z ``` ## 數值微分 從數值上說,最簡單的方案是去計算導數的近似值。回憶`h(x)`在 ![x_0](https://img.kancloud.cn/46/08/46082f7d6471c3fabb832d8f94075758_16x11.gif) 的導數 ![h^{'}(x_0)](https://img.kancloud.cn/89/14/89145d6b263966722529e2afb50b19ed_45x21.gif),是該函數在該點處的斜率,或者更準確如公式 D-2 所示。 ![E_D-2](https://img.kancloud.cn/6a/98/6a98f2f1de8e30e0c4cb2911d2bc4014_622x220.png) 因此如果我們想要計算 ![f(x,y)](https://img.kancloud.cn/56/b5/56b5f89bd3ffde69293aeb8cea7e8bfd_51x18.gif) 關于`x`,在 ![x=3, y=4](https://img.kancloud.cn/e2/aa/e2aaf7b7ea4190534d4ac26a8ad006bd_94x16.gif) 處的導數,我們可以簡單計算 ![f(3+\epsilon, 4) - f(3, 4)](https://img.kancloud.cn/7b/dc/7bdce5700a0fa919cbca69b64ad10271_152x18.gif) 的值,將這個結果除以 ![\epsilon](https://img.kancloud.cn/f1/f4/f1f442a329c8d3df85dce68831d660fe_7x8.jpg),且 ![\epsilon](https://img.kancloud.cn/f1/f4/f1f442a329c8d3df85dce68831d660fe_7x8.jpg) 去很小的值。這個過程正是如下的代碼所要干的。 ```python def f(x, y): return x**2*y + y + 2 def derivative(f, x, y, x_eps, y_eps): return (f(x + x_eps, y + y_eps) - f(x, y)) / (x_eps + y_eps) df_dx = derivative(f, 3, 4, 0.00001, 0) df_dy = derivative(f, 3, 4, 0, 0.00001) ``` 不幸的是,偏導的結果并不準確(并且可能在求解復雜函數時更糟糕)。上述正確答案分別是 24 和 10 ,但我們得到的是: ```python >>> print(df_dx) 24.000039999805264 >>> print(df_dy) 10.000000000331966 ``` 注意到為了計算兩個偏導數, 我們不得不調用`f()`至少三次(在上述代碼里我們調用了四次,但可以優化)。如果存在 1000 個參數,我們將會調用`f()`至少 1001 次。當處理大的神經網絡時,這樣的操作很沒有效率。 然而,數值微分實現起來如此簡單,以至于它是檢查其他方法正確性的優秀工具。例如,如果它的結果與您手動計算的導數不同,那么你的導數可能包含錯誤。 ## 前向自動微分 前向自動微分既不是數值微分,也不是符號微分,但在某些方面,它是他們的愛情結晶。它依賴對偶數。對偶數是奇怪但迷人的,是 ![a + b\epsilon](https://img.kancloud.cn/7f/1b/7f1bb30d051a46e6b04ec4069b44e7d5_47x15.gif) 形式的數,這里`a`和`b`是實數,![\epsilon](https://img.kancloud.cn/f1/f4/f1f442a329c8d3df85dce68831d660fe_7x8.jpg) 是無窮小的數,滿足 ![\epsilon ^ 2 = 0](https://img.kancloud.cn/c6/cc/c6cc30cdb24ab2dac1e76588c402c1dc_48x16.gif),但 ![\epsilon \ne 0](https://img.kancloud.cn/8b/0e/8b0ee45e42addceeac0f1ab949ae7b66_40x18.gif)。你可以認為對偶數 ![42 + 24\epsilon](https://img.kancloud.cn/42/9e/429ebed428aab62a7ee7fdd3f60173af_65x14.gif) 類似于有著無窮個 0 的 42.0000?000024(但當然這是簡化后的,僅僅給你對偶數什么的想法)。一個對偶數在內存中表示為一個浮點數對,例如,![42 + 24\epsilon](https://img.kancloud.cn/42/9e/429ebed428aab62a7ee7fdd3f60173af_65x14.gif) 表示為`(42.0, 24.0)`。 對偶數可相加、相乘、等等操作,正如公式 D-3 所示。 ![E_D-3](https://img.kancloud.cn/6f/41/6f41581d268f5944b1f74b9d21843986_722x183.png) 最重要的,可證明`h(a + b?) = h(a) + b × h'(a)?`,所以計算一次`h(a + ?)`就得到了兩個值`h(a)`和`h'(a)`。圖 D-2 展示了前向自動微分如何計算 ![f(x,y)=x^2y + y + 2](https://img.kancloud.cn/84/f5/84f51a1c782f49b88f5f584262ed7d40_166x20.gif) 關于`x`,在 ![x=3, y=4](https://img.kancloud.cn/e2/aa/e2aaf7b7ea4190534d4ac26a8ad006bd_94x16.gif) 處的導數。我們所要做的一切只是計算 ![f(3+\epsilon, 4)](https://img.kancloud.cn/91/83/9183f3a9fa7479c3cbcaceb1139bac79_79x18.gif);它將輸出一個對偶數,其第一部分等于 ![f(3, 4)](https://img.kancloud.cn/d6/7a/d67af86988871251de3e79dbf5af200a_50x18.gif),第二部分等于 ![f^{'}(3, 4) = \frac{\partial f}{\partial x} (3,4)](https://img.kancloud.cn/d4/ea/d4eae45d90e3dce416dff2ad3f866bc7_143x39.gif)。 ![D-2](https://img.kancloud.cn/33/a5/33a54efdb1579f40dabbc1c7769c26f0_760x638.png) 為了計算 ![\frac{\partial f}{\partial y} (3,4)](https://img.kancloud.cn/a8/c5/a8c507b925ddf6cc1fd878231cee58b4_62x42.gif) 我們不得不再遍歷一遍計算圖,但這次前饋的值為 ![x=3, y = 4 + \epsilon](https://img.kancloud.cn/4a/8d/4a8d3512abe31ea635ae3550ba5c617d_123x16.gif)。 所以前向自動微分比數值微分準確得多,但它遭受同樣的缺陷:如果有 1000 個參數,那為了計算所有的偏導數,得歷經計算圖 1000 次。這正是反向自動微分耀眼的地方:計算所有的偏導數,它只需要遍歷計算圖 2 次。 ## 反向自動微分 反向自動微分是 TensorFlow 采取的方案。它首先前饋遍歷計算圖(即,從輸入到輸出),計算出每個節點的值。然后進行第二次遍歷,這次是反向遍歷(即,從輸出到輸入),計算出所有的偏導數。圖 D-3 展示了第二次遍歷的過程。在第一次遍歷過程中,所有節點值已被計算,輸入是 ![x=3, y=4](https://img.kancloud.cn/e2/aa/e2aaf7b7ea4190534d4ac26a8ad006bd_94x16.gif)。你可以在每個節點底部右方看到這些值(例如,![x \times x = 9](https://img.kancloud.cn/82/64/82648b22027f31599b4e10c56b0082eb_76x12.gif))。節點已被標號,從 ![n_1](https://img.kancloud.cn/d6/ba/d6baf45f28b535f30a864415b4130c52_17x12.jpg) 到 ![n_7](https://img.kancloud.cn/80/3f/803fb7016ca56ce07782ba9ebface325_18x11.gif)。輸出節點是 ![n_7: f(3, 4) = n_7 = 42](https://img.kancloud.cn/ab/09/ab095df113f3666ac41ab7377454f4a7_168x18.gif)。 ![D-3](https://img.kancloud.cn/74/a0/74a020a33d0d4a52e731bfbfd2acadce_765x590.png) 這個計算關于每個連續節點的偏導數的思想逐漸地從上到下遍歷圖,直到到達變量節點。為實現這個,反向自動微分強烈依賴于鏈式法則,如公式 D-4 所示。 ![E_D-4](https://img.kancloud.cn/65/9d/659d14db2f4ca7302c4a38f5f5874176_369x113.png) 由于 ![n_7](https://img.kancloud.cn/80/3f/803fb7016ca56ce07782ba9ebface325_18x11.gif) 是輸出節點,即 ![f= n_7](https://img.kancloud.cn/f2/20/f220da9bd15e8b6d9e5d1d7b4ed738b6_53x16.gif),所以 ![\frac{\partial f}{\partial n_7} = 1](https://img.kancloud.cn/ce/78/ce781ce6a126062d276e5ad50d89a52f_62x41.gif)。 接著到了圖的 ![n_5](https://img.kancloud.cn/64/88/64885a24bbaaf5ea9cb3a3a6246771c2_17x11.gif) 節點:當 ![n_5](https://img.kancloud.cn/64/88/64885a24bbaaf5ea9cb3a3a6246771c2_17x11.gif) 變化時,![f](https://img.kancloud.cn/18/8e/188ee644e8202aad30eac11166858841_10x16.gif) 會變化多少?答案是 ![\frac{\partial f}{\partial n_5} = \frac{\partial f}{\partial n_7} \times \frac{\partial n_7}{\partial n_5}](https://img.kancloud.cn/5a/19/5a194c124999f2d23231948cf07219d1_139x41.gif)。我們已經知道 ![\frac{\partial f}{\partial n_7} = 1](https://img.kancloud.cn/ce/78/ce781ce6a126062d276e5ad50d89a52f_62x41.gif),因此我們只需要知道 ![\frac{\partial n_7}{\partial n_5}](https://img.kancloud.cn/a7/ff/a7ff39d50d242ac765b8a5f62fdc3c17_29x41.gif) 就行。因為 ![n_7](https://img.kancloud.cn/80/3f/803fb7016ca56ce07782ba9ebface325_18x11.gif) 是 ![n_5 + n_6](https://img.kancloud.cn/b2/2e/b22e70fa0128f957ccac6b94a2e1b03b_57x14.gif) 的和,因此可得到 ![\frac{\partial n_7}{\partial n_5} = 1](https://img.kancloud.cn/42/3f/423f200d46c9a9a9002ecd2bc082e097_62x41.gif),因此 ![\frac{\partial f}{\partial n_5}=1 \times 1 = 1](https://img.kancloud.cn/fd/0f/fd0f3fa064aaf3eabd0aedffe01a0b64_127x41.gif)。 現在前進到 ![n_4](https://img.kancloud.cn/48/2b/482b4f1dbb7f8b26c49138d2d074308d_18x11.gif):當 ![n_4](https://img.kancloud.cn/48/2b/482b4f1dbb7f8b26c49138d2d074308d_18x11.gif) 變化時,![f](https://img.kancloud.cn/18/8e/188ee644e8202aad30eac11166858841_10x16.gif) 會變化多少?答案是 ![\frac{\partial f}{\partial n_4} = \frac{\partial f}{\partial n_5} \times \frac{\partial n_5}{\partial n_4}](https://img.kancloud.cn/88/b2/88b25becabedd1329cb373a814bf7ee1_139x41.gif)。由于 ![n_5 = n_4 \times n_2](https://img.kancloud.cn/e3/54/e354e58ead9bc5ba1b63d92b2e3f8f1d_99x12.gif),我們可得到 ![\frac{\partial n_5}{\partial n_4} = n_2](https://img.kancloud.cn/ee/dc/eedc836f2242ab4526e7fe426c255820_71x41.gif),所以 ![\frac{\partial f}{\partial n_4}= 1 \times n_2 = 4](https://img.kancloud.cn/8e/5e/8e5ec50ec7baa31ae92aad71a237d9df_136x41.gif)。 這個遍歷過程一直持續,此時我們達到圖的底部。這時我們已經得到了所有偏導數在點 ![x=3, y=4](https://img.kancloud.cn/e2/aa/e2aaf7b7ea4190534d4ac26a8ad006bd_94x16.gif) 處的值。在這個例子里,我們得到 ![\frac{\partial f}{\partial x} = 24, \frac{\partial f}{\partial y} = 10](https://img.kancloud.cn/b6/98/b6986e1e3f178430f72c7d14a0608826_140x42.gif)。聽起來很美妙! 反向自動微分是非常強大且準確的技術,尤其是當有很多輸入參數和極少輸出時,因為它只要求一次前饋傳遞加上一次反向傳遞,就可計算所有輸出關于所有輸入的偏導數。最重要的是,它可以處理任意代碼定義的函數。它也可以處理那些不完全可微的函數,只要 你要求他計算的偏導數在該點處是可微的。 如果你在 TensorFlow 中實現了新算子,你想使它與現有的自動微分相兼容,那你需要提供函數,該函數用于構建一個子圖,來計算關于新算子輸入的偏導數。例如,假設你實現了一個計算其輸入的平方的函數,平方算子 ![f(x)= x ^2](https://img.kancloud.cn/e9/60/e960ebb8a09a606aa966e44b93ea076a_75x20.gif),在這個例子中你需要提供相應的導函數 ![f^{'}(x)= 2x ](https://img.kancloud.cn/f6/89/f68957bd403ae5772d4b1cddabee6fa8_83x21.gif)。注意這個導函數不計算一個數值結果,而是用于構建子圖,該子圖后續將計算偏導結果。這是非常有用的,因為這意味著你可以計算梯度的梯度(為了計算二階導數,或者甚至更高階的導數)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看