You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

autograd.py 6.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. # -*- coding: utf-8 -*-
  2. # ---
  3. # jupyter:
  4. # jupytext_format_version: '1.2'
  5. # kernelspec:
  6. # display_name: Python 3
  7. # language: python
  8. # name: python3
  9. # language_info:
  10. # codemirror_mode:
  11. # name: ipython
  12. # version: 3
  13. # file_extension: .py
  14. # mimetype: text/x-python
  15. # name: python
  16. # nbconvert_exporter: python
  17. # pygments_lexer: ipython3
  18. # version: 3.5.2
  19. # ---
  20. # # 自动求导
  21. # 这次课程我们会了解 PyTorch 中的自动求导机制,自动求导是 PyTorch 中非常重要的特性,能够让我们避免手动去计算非常复杂的导数,这能够极大地减少了我们构建模型的时间,这也是其前身 Torch 这个框架所不具备的特性,下面我们通过例子看看 PyTorch 自动求导的独特魅力以及探究自动求导的更多用法。
  22. import torch
  23. from torch.autograd import Variable
  24. # ## 简单情况的自动求导
  25. # 下面我们显示一些简单情况的自动求导,"简单"体现在计算的结果都是标量,也就是一个数,我们对这个标量进行自动求导。
  26. x = Variable(torch.Tensor([2]), requires_grad=True)
  27. y = x + 2
  28. z = y ** 2 + 3
  29. print(z)
  30. # 通过上面的一些列操作,我们从 x 得到了最后的结果out,我们可以将其表示为数学公式
  31. #
  32. # $$
  33. # z = (x + 2)^2 + 3
  34. # $$
  35. #
  36. # 那么我们从 z 对 x 求导的结果就是
  37. #
  38. # $$
  39. # \frac{\partial z}{\partial x} = 2 (x + 2) = 2 (2 + 2) = 8
  40. # $$
  41. # 如果你对求导不熟悉,可以查看以下[网址进行复习](https://baike.baidu.com/item/%E5%AF%BC%E6%95%B0#1)
  42. # 使用自动求导
  43. z.backward()
  44. print(x.grad)
  45. # 对于上面这样一个简单的例子,我们验证了自动求导,同时可以发现发现使用自动求导非常方便。如果是一个更加复杂的例子,那么手动求导就会显得非常的麻烦,所以自动求导的机制能够帮助我们省去麻烦的数学计算,下面我们可以看一个更加复杂的例子。
  46. # +
  47. x = Variable(torch.randn(10, 20), requires_grad=True)
  48. y = Variable(torch.randn(10, 5), requires_grad=True)
  49. w = Variable(torch.randn(20, 5), requires_grad=True)
  50. out = torch.mean(y - torch.matmul(x, w)) # torch.matmul 是做矩阵乘法
  51. out.backward()
  52. # -
  53. # 如果你对矩阵乘法不熟悉,可以查看下面的[网址进行复习](https://baike.baidu.com/item/%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95/5446029?fr=aladdin)
  54. # 得到 x 的梯度
  55. print(x.grad)
  56. # 得到 y 的的梯度
  57. print(y.grad)
  58. # 得到 w 的梯度
  59. print(w.grad)
  60. # 上面数学公式就更加复杂,矩阵乘法之后对两个矩阵对应元素相乘,然后所有元素求平均,有兴趣的同学可以手动去计算一下梯度,使用 PyTorch 的自动求导,我们能够非常容易得到 x, y 和 w 的导数,因为深度学习中充满大量的矩阵运算,所以我们没有办法手动去求这些导数,有了自动求导能够非常方便地解决网络更新的问题。
  61. #
  62. #
  63. # ## 复杂情况的自动求导
  64. # 上面我们展示了简单情况下的自动求导,都是对标量进行自动求导,可能你会有一个疑问,如何对一个向量或者矩阵自动求导了呢?感兴趣的同学可以自己先去尝试一下,下面我们会介绍对多维数组的自动求导机制。
  65. m = Variable(torch.FloatTensor([[2, 3]]), requires_grad=True) # 构建一个 1 x 2 的矩阵
  66. n = Variable(torch.zeros(1, 2)) # 构建一个相同大小的 0 矩阵
  67. print(m)
  68. print(n)
  69. # 通过 m 中的值计算新的 n 中的值
  70. n[0, 0] = m[0, 0] ** 2
  71. n[0, 1] = m[0, 1] ** 3
  72. print(n)
  73. # 将上面的式子写成数学公式,可以得到
  74. # $$
  75. # n = (n_0,\ n_1) = (m_0^2,\ m_1^3) = (2^2,\ 3^3)
  76. # $$
  77. # 下面我们直接对 n 进行反向传播,也就是求 n 对 m 的导数。
  78. #
  79. # 这时我们需要明确这个导数的定义,即如何定义
  80. #
  81. # $$
  82. # \frac{\partial n}{\partial m} = \frac{\partial (n_0,\ n_1)}{\partial (m_0,\ m_1)}
  83. # $$
  84. #
  85. # 在 PyTorch 中,如果要调用自动求导,需要往`backward()`中传入一个参数,这个参数的形状和 n 一样大,比如是 $(w_0,\ w_1)$,那么自动求导的结果就是:
  86. # $$
  87. # \frac{\partial n}{\partial m_0} = w_0 \frac{\partial n_0}{\partial m_0} + w_1 \frac{\partial n_1}{\partial m_0}
  88. # $$
  89. # $$
  90. # \frac{\partial n}{\partial m_1} = w_0 \frac{\partial n_0}{\partial m_1} + w_1 \frac{\partial n_1}{\partial m_1}
  91. # $$
  92. n.backward(torch.ones_like(n)) # 将 (w0, w1) 取成 (1, 1)
  93. print(m.grad)
  94. # 通过自动求导我们得到了梯度是 4 和 27,我们可以验算一下
  95. # $$
  96. # \frac{\partial n}{\partial m_0} = w_0 \frac{\partial n_0}{\partial m_0} + w_1 \frac{\partial n_1}{\partial m_0} = 2 m_0 + 0 = 2 \times 2 = 4
  97. # $$
  98. # $$
  99. # \frac{\partial n}{\partial m_1} = w_0 \frac{\partial n_0}{\partial m_1} + w_1 \frac{\partial n_1}{\partial m_1} = 0 + 3 m_1^2 = 3 \times 3^2 = 27
  100. # $$
  101. # 通过验算我们可以得到相同的结果
  102. #
  103. #
  104. # ## 多次自动求导
  105. # 通过调用 backward 我们可以进行一次自动求导,如果我们再调用一次 backward,会发现程序报错,没有办法再做一次。这是因为 PyTorch 默认做完一次自动求导之后,计算图就被丢弃了,所以两次自动求导需要手动设置一个东西,我们通过下面的小例子来说明。
  106. x = Variable(torch.FloatTensor([3]), requires_grad=True)
  107. y = x * 2 + x ** 2 + 3
  108. print(y)
  109. y.backward(retain_graph=True) # 设置 retain_graph 为 True 来保留计算图
  110. print(x.grad)
  111. y.backward() # 再做一次自动求导,这次不保留计算图
  112. print(x.grad)
  113. # 可以发现 x 的梯度变成了 16,因为这里做了两次自动求导,所以讲第一次的梯度 8 和第二次的梯度 8 加起来得到了 16 的结果。
  114. #
  115. #
  116. # **小练习**
  117. #
  118. # 定义
  119. #
  120. # $$
  121. # x =
  122. # \left[
  123. # \begin{matrix}
  124. # x_0 \\
  125. # x_1
  126. # \end{matrix}
  127. # \right] =
  128. # \left[
  129. # \begin{matrix}
  130. # 2 \\
  131. # 3
  132. # \end{matrix}
  133. # \right]
  134. # $$
  135. #
  136. # $$
  137. # k = (k_0,\ k_1) = (x_0^2 + 3 x_1,\ 2 x_0 + x_1^2)
  138. # $$
  139. #
  140. # 我们希望求得
  141. #
  142. # $$
  143. # j = \left[
  144. # \begin{matrix}
  145. # \frac{\partial k_0}{\partial x_0} & \frac{\partial k_0}{\partial x_1} \\
  146. # \frac{\partial k_1}{\partial x_0} & \frac{\partial k_1}{\partial x_1}
  147. # \end{matrix}
  148. # \right]
  149. # $$
  150. #
  151. # 参考答案:
  152. #
  153. # $$
  154. # \left[
  155. # \begin{matrix}
  156. # 4 & 3 \\
  157. # 2 & 6 \\
  158. # \end{matrix}
  159. # \right]
  160. # $$
  161. # +
  162. x = Variable(torch.FloatTensor([2, 3]), requires_grad=True)
  163. k = Variable(torch.zeros(2))
  164. k[0] = x[0] ** 2 + 3 * x[1]
  165. k[1] = x[1] ** 2 + 2 * x[0]
  166. # -
  167. print(k)
  168. # +
  169. j = torch.zeros(2, 2)
  170. k.backward(torch.FloatTensor([1, 0]), retain_graph=True)
  171. j[0] = x.grad.data
  172. x.grad.data.zero_() # 归零之前求得的梯度
  173. k.backward(torch.FloatTensor([0, 1]))
  174. j[1] = x.grad.data
  175. # -
  176. print(j)
  177. # 下一次课我们会介绍两种神经网络的编程方式,动态图编程和静态图编程

机器学习越来越多应用到飞行器、机器人等领域,其目的是利用计算机实现类似人类的智能,从而实现装备的智能化与无人化。本课程旨在引导学生掌握机器学习的基本知识、典型方法与技术,通过具体的应用案例激发学生对该学科的兴趣,鼓励学生能够从人工智能的角度来分析、解决飞行器、机器人所面临的问题和挑战。本课程主要内容包括Python编程基础,机器学习模型,无监督学习、监督学习、深度学习基础知识与实现,并学习如何利用机器学习解决实际问题,从而全面提升自我的《综合能力》。