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.

2-autograd.ipynb 22 kB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. {
  2. "cells": [
  3. {
  4. "cell_type": "markdown",
  5. "metadata": {},
  6. "source": [
  7. "# 自动求导\n",
  8. "这次课程我们会了解 PyTorch 中的自动求导机制,自动求导是 PyTorch 中非常重要的特性,能够让我们避免手动去计算非常复杂的导数,这能够极大地减少了我们构建模型的时间,这也是其前身 Torch 这个框架所不具备的特性,下面我们通过例子看看 PyTorch 自动求导的独特魅力以及探究自动求导的更多用法。"
  9. ]
  10. },
  11. {
  12. "cell_type": "code",
  13. "execution_count": 1,
  14. "metadata": {},
  15. "outputs": [],
  16. "source": [
  17. "import torch\n",
  18. "from torch.autograd import Variable"
  19. ]
  20. },
  21. {
  22. "cell_type": "markdown",
  23. "metadata": {},
  24. "source": [
  25. "## 简单情况的自动求导\n",
  26. "下面我们显示一些简单情况的自动求导,\"简单\"体现在计算的结果都是标量,也就是一个数,我们对这个标量进行自动求导。"
  27. ]
  28. },
  29. {
  30. "cell_type": "code",
  31. "execution_count": 3,
  32. "metadata": {},
  33. "outputs": [
  34. {
  35. "name": "stdout",
  36. "output_type": "stream",
  37. "text": [
  38. "tensor([19.], grad_fn=<AddBackward0>)\n"
  39. ]
  40. }
  41. ],
  42. "source": [
  43. "x = Variable(torch.Tensor([2]), requires_grad=True)\n",
  44. "y = x + 2\n",
  45. "z = y ** 2 + 3\n",
  46. "print(z)"
  47. ]
  48. },
  49. {
  50. "cell_type": "markdown",
  51. "metadata": {},
  52. "source": [
  53. "通过上面的一些列操作,我们从 x 得到了最后的结果out,我们可以将其表示为数学公式\n",
  54. "\n",
  55. "$$\n",
  56. "z = (x + 2)^2 + 3\n",
  57. "$$\n",
  58. "\n",
  59. "那么我们从 z 对 x 求导的结果就是 \n",
  60. "\n",
  61. "$$\n",
  62. "\\frac{\\partial z}{\\partial x} = 2 (x + 2) = 2 (2 + 2) = 8\n",
  63. "$$\n",
  64. "如果你对求导不熟悉,可以查看以下[网址进行复习](https://baike.baidu.com/item/%E5%AF%BC%E6%95%B0#1)"
  65. ]
  66. },
  67. {
  68. "cell_type": "code",
  69. "execution_count": 4,
  70. "metadata": {},
  71. "outputs": [
  72. {
  73. "name": "stdout",
  74. "output_type": "stream",
  75. "text": [
  76. "tensor([8.])\n"
  77. ]
  78. }
  79. ],
  80. "source": [
  81. "# 使用自动求导\n",
  82. "z.backward()\n",
  83. "print(x.grad)"
  84. ]
  85. },
  86. {
  87. "cell_type": "markdown",
  88. "metadata": {},
  89. "source": [
  90. "对于上面这样一个简单的例子,我们验证了自动求导,同时可以发现发现使用自动求导非常方便。如果是一个更加复杂的例子,那么手动求导就会显得非常的麻烦,所以自动求导的机制能够帮助我们省去麻烦的数学计算,下面我们可以看一个更加复杂的例子。"
  91. ]
  92. },
  93. {
  94. "cell_type": "code",
  95. "execution_count": 9,
  96. "metadata": {},
  97. "outputs": [
  98. {
  99. "name": "stdout",
  100. "output_type": "stream",
  101. "text": [
  102. "tensor([[ 5.7436e-01, -8.5241e-01, 2.2845e+00, 3.6574e-01, 1.4336e+00,\n",
  103. " 6.2769e-01, -2.4378e-01, 2.3407e+00, 3.8966e-01, 1.1835e+00,\n",
  104. " -6.4391e-01, 9.1353e-01, -5.8734e-01, -1.9392e+00, 9.3507e-01,\n",
  105. " 8.8518e-02, 7.2412e-01, -1.0687e+00, -6.7646e-01, 1.2672e+00],\n",
  106. " [ 7.2998e-01, 2.0229e+00, -5.0831e-01, -6.3940e-01, -8.7033e-01,\n",
  107. " 2.7687e-01, 6.3498e-01, -1.8736e-03, -8.4395e-01, 1.4696e+00,\n",
  108. " -1.7850e+00, -4.5297e-01, 9.2144e-01, 8.5070e-02, -5.8926e-01,\n",
  109. " 1.2085e+00, -9.7894e-01, -3.4309e-01, -2.4711e-02, -6.4475e-01],\n",
  110. " [-2.8774e-01, 1.2039e+00, -5.2320e-01, 1.3787e-01, 3.9971e-02,\n",
  111. " -5.6454e-01, -1.5835e+00, -2.0742e-01, -1.4274e+00, -3.7860e-01,\n",
  112. " 6.2642e-01, 1.6408e+00, -1.1916e-01, 1.4388e-01, -9.5261e-01,\n",
  113. " 4.0784e-01, 8.1715e-01, 3.9228e-01, 4.1611e-01, -3.3709e-01],\n",
  114. " [ 3.3040e-01, 1.7915e-01, -5.7069e-02, 1.1144e+00, -1.0322e+00,\n",
  115. " 9.9129e-01, 1.1692e+00, 7.9638e-01, -1.0943e-01, 8.2714e-01,\n",
  116. " -1.5700e-01, -5.6686e-01, -1.9550e-01, -1.2263e+00, 1.7836e+00,\n",
  117. " 9.1989e-01, -6.4577e-01, 9.5402e-01, -8.6525e-01, 3.9199e-01],\n",
  118. " [-8.8085e-01, -6.3551e-03, 1.6959e+00, -7.5292e-02, -8.8929e-02,\n",
  119. " 1.0209e+00, 8.9355e-01, -1.2029e+00, 1.9429e+00, -2.7024e-01,\n",
  120. " -9.1289e-01, -1.3788e+00, -6.2695e-01, -6.5776e-01, 3.3640e-01,\n",
  121. " -1.0473e-01, 9.9417e-01, 1.0128e+00, 2.4199e+00, 2.8859e-01],\n",
  122. " [ 8.0469e-02, -1.6585e-01, -4.9862e-01, -5.5413e-01, -4.9307e-01,\n",
  123. " -7.3808e-01, 1.3946e-02, 5.6282e-01, 9.1096e-01, -1.9281e-01,\n",
  124. " -3.8546e-01, -1.4070e+00, 7.3520e-01, 1.7412e+00, 1.0770e+00,\n",
  125. " 1.4837e+00, -7.4241e-01, -4.0977e-01, 1.1057e+00, -7.0222e-01],\n",
  126. " [-2.3147e-01, -3.7781e-01, 1.0774e+00, -7.9918e-01, 1.8275e+00,\n",
  127. " 7.6937e-01, -2.7600e-01, 1.0389e+00, 1.4457e+00, -1.2898e+00,\n",
  128. " 1.2761e-03, 5.5406e-01, 1.8231e+00, -2.3874e-01, 1.2145e+00,\n",
  129. " -2.1051e+00, -6.6464e-01, -8.5335e-01, -2.6258e-01, 8.0080e-01],\n",
  130. " [ 4.2173e-01, 1.7040e-01, -3.0126e-01, -5.2095e-01, 5.5845e-01,\n",
  131. " 5.9780e-01, -6.8320e-01, -5.2203e-01, 4.9485e-01, -8.2392e-01,\n",
  132. " -1.7584e-01, -1.3862e+00, 1.3604e+00, -7.5567e-01, 3.1400e-01,\n",
  133. " 1.8617e+00, -1.1887e+00, -3.1732e-01, -1.5062e-01, -1.7251e-01],\n",
  134. " [ 1.0924e+00, 1.0899e+00, 5.7135e-01, -2.7047e-01, 1.1123e+00,\n",
  135. " 9.3634e-01, -1.4739e+00, 5.3640e-01, -8.2090e-02, 3.3112e-02,\n",
  136. " 6.6032e-01, 1.1448e+00, -4.2457e-01, 1.2898e+00, 3.9002e-01,\n",
  137. " 2.7646e-01, 9.6717e-03, -1.7425e-01, -1.9732e-01, 9.7876e-01],\n",
  138. " [ 4.4554e-01, 5.3807e-01, -2.2031e-02, 1.3198e+00, -1.1642e+00,\n",
  139. " -6.6617e-01, -2.6982e-01, -1.0219e+00, 5.8154e-01, 1.7617e+00,\n",
  140. " 3.3077e-01, 1.5238e+00, -5.8909e-01, 1.1373e+00, 1.0998e+00,\n",
  141. " -1.8168e+00, -5.0699e-01, 4.0043e-01, -2.3226e+00, 7.2522e-02]],\n",
  142. " requires_grad=True)\n"
  143. ]
  144. }
  145. ],
  146. "source": [
  147. "# FIXME: the demo need improve\n",
  148. "x = Variable(torch.randn(10, 20), requires_grad=True)\n",
  149. "y = Variable(torch.randn(10, 5), requires_grad=True)\n",
  150. "w = Variable(torch.randn(20, 5), requires_grad=True)\n",
  151. "print(x)\n",
  152. "out = torch.mean(y - torch.matmul(x, w)) # torch.matmul 是做矩阵乘法\n",
  153. "out.backward()"
  154. ]
  155. },
  156. {
  157. "cell_type": "markdown",
  158. "metadata": {},
  159. "source": [
  160. "如果你对矩阵乘法不熟悉,可以查看下面的[网址进行复习](https://baike.baidu.com/item/%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95/5446029?fr=aladdin)"
  161. ]
  162. },
  163. {
  164. "cell_type": "code",
  165. "execution_count": 6,
  166. "metadata": {},
  167. "outputs": [
  168. {
  169. "name": "stdout",
  170. "output_type": "stream",
  171. "text": [
  172. "tensor([[ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  173. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  174. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  175. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  176. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  177. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  178. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  179. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  180. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  181. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  182. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  183. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  184. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  185. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  186. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  187. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  188. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  189. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  190. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  191. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  192. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  193. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  194. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  195. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  196. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  197. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  198. " 0.0221, -0.0324, -0.0601, 0.0048],\n",
  199. " [ 0.0034, -0.0301, -0.0040, -0.0488, 0.0187, -0.0139, -0.0374, 0.0102,\n",
  200. " 0.0337, -0.0249, -0.0777, -0.0868, 0.0132, 0.0042, -0.0627, -0.0448,\n",
  201. " 0.0221, -0.0324, -0.0601, 0.0048]])\n"
  202. ]
  203. }
  204. ],
  205. "source": [
  206. "# 得到 x 的梯度\n",
  207. "print(x.grad)"
  208. ]
  209. },
  210. {
  211. "cell_type": "code",
  212. "execution_count": 7,
  213. "metadata": {},
  214. "outputs": [
  215. {
  216. "name": "stdout",
  217. "output_type": "stream",
  218. "text": [
  219. "tensor([[0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  220. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  221. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  222. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  223. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  224. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  225. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  226. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  227. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200],\n",
  228. " [0.0200, 0.0200, 0.0200, 0.0200, 0.0200]])\n"
  229. ]
  230. }
  231. ],
  232. "source": [
  233. "# 得到 y 的的梯度\n",
  234. "print(y.grad)"
  235. ]
  236. },
  237. {
  238. "cell_type": "code",
  239. "execution_count": 8,
  240. "metadata": {},
  241. "outputs": [
  242. {
  243. "name": "stdout",
  244. "output_type": "stream",
  245. "text": [
  246. "tensor([[ 0.0172, 0.0172, 0.0172, 0.0172, 0.0172],\n",
  247. " [ 0.0389, 0.0389, 0.0389, 0.0389, 0.0389],\n",
  248. " [-0.0748, -0.0748, -0.0748, -0.0748, -0.0748],\n",
  249. " [-0.0186, -0.0186, -0.0186, -0.0186, -0.0186],\n",
  250. " [ 0.0278, 0.0278, 0.0278, 0.0278, 0.0278],\n",
  251. " [-0.0228, -0.0228, -0.0228, -0.0228, -0.0228],\n",
  252. " [-0.0496, -0.0496, -0.0496, -0.0496, -0.0496],\n",
  253. " [-0.0084, -0.0084, -0.0084, -0.0084, -0.0084],\n",
  254. " [ 0.0693, 0.0693, 0.0693, 0.0693, 0.0693],\n",
  255. " [-0.0821, -0.0821, -0.0821, -0.0821, -0.0821],\n",
  256. " [ 0.0419, 0.0419, 0.0419, 0.0419, 0.0419],\n",
  257. " [-0.0126, -0.0126, -0.0126, -0.0126, -0.0126],\n",
  258. " [ 0.0322, 0.0322, 0.0322, 0.0322, 0.0322],\n",
  259. " [ 0.0863, 0.0863, 0.0863, 0.0863, 0.0863],\n",
  260. " [-0.0791, -0.0791, -0.0791, -0.0791, -0.0791],\n",
  261. " [ 0.0179, 0.0179, 0.0179, 0.0179, 0.0179],\n",
  262. " [-0.1109, -0.1109, -0.1109, -0.1109, -0.1109],\n",
  263. " [-0.0188, -0.0188, -0.0188, -0.0188, -0.0188],\n",
  264. " [-0.0636, -0.0636, -0.0636, -0.0636, -0.0636],\n",
  265. " [ 0.0223, 0.0223, 0.0223, 0.0223, 0.0223]])\n"
  266. ]
  267. }
  268. ],
  269. "source": [
  270. "# 得到 w 的梯度\n",
  271. "print(w.grad)"
  272. ]
  273. },
  274. {
  275. "cell_type": "markdown",
  276. "metadata": {},
  277. "source": [
  278. "上面数学公式就更加复杂,矩阵乘法之后对两个矩阵对应元素相乘,然后所有元素求平均,有兴趣的同学可以手动去计算一下梯度,使用 PyTorch 的自动求导,我们能够非常容易得到 x, y 和 w 的导数,因为深度学习中充满大量的矩阵运算,所以我们没有办法手动去求这些导数,有了自动求导能够非常方便地解决网络更新的问题。"
  279. ]
  280. },
  281. {
  282. "cell_type": "markdown",
  283. "metadata": {},
  284. "source": [
  285. "\n"
  286. ]
  287. },
  288. {
  289. "cell_type": "markdown",
  290. "metadata": {},
  291. "source": [
  292. "## 复杂情况的自动求导\n",
  293. "上面我们展示了简单情况下的自动求导,都是对标量进行自动求导,可能你会有一个疑问,如何对一个向量或者矩阵自动求导了呢?感兴趣的同学可以自己先去尝试一下,下面我们会介绍对多维数组的自动求导机制。"
  294. ]
  295. },
  296. {
  297. "cell_type": "code",
  298. "execution_count": 11,
  299. "metadata": {},
  300. "outputs": [
  301. {
  302. "name": "stdout",
  303. "output_type": "stream",
  304. "text": [
  305. "tensor([[2., 3.]], requires_grad=True)\n",
  306. "tensor([[0., 0.]])\n"
  307. ]
  308. }
  309. ],
  310. "source": [
  311. "m = Variable(torch.FloatTensor([[2, 3]]), requires_grad=True) # 构建一个 1 x 2 的矩阵\n",
  312. "n = Variable(torch.zeros(1, 2)) # 构建一个相同大小的 0 矩阵\n",
  313. "print(m)\n",
  314. "print(n)"
  315. ]
  316. },
  317. {
  318. "cell_type": "code",
  319. "execution_count": 13,
  320. "metadata": {},
  321. "outputs": [
  322. {
  323. "name": "stdout",
  324. "output_type": "stream",
  325. "text": [
  326. "tensor(2., grad_fn=<SelectBackward>)\n",
  327. "tensor([[ 4., 27.]], grad_fn=<CopySlices>)\n"
  328. ]
  329. }
  330. ],
  331. "source": [
  332. "# 通过 m 中的值计算新的 n 中的值\n",
  333. "print(m[0,0])\n",
  334. "n[0, 0] = m[0, 0] ** 2\n",
  335. "n[0, 1] = m[0, 1] ** 3\n",
  336. "print(n)"
  337. ]
  338. },
  339. {
  340. "cell_type": "markdown",
  341. "metadata": {},
  342. "source": [
  343. "将上面的式子写成数学公式,可以得到 \n",
  344. "$$\n",
  345. "n = (n_0,\\ n_1) = (m_0^2,\\ m_1^3) = (2^2,\\ 3^3) \n",
  346. "$$"
  347. ]
  348. },
  349. {
  350. "cell_type": "markdown",
  351. "metadata": {},
  352. "source": [
  353. "下面我们直接对 n 进行反向传播,也就是求 n 对 m 的导数。\n",
  354. "\n",
  355. "这时我们需要明确这个导数的定义,即如何定义\n",
  356. "\n",
  357. "$$\n",
  358. "\\frac{\\partial n}{\\partial m} = \\frac{\\partial (n_0,\\ n_1)}{\\partial (m_0,\\ m_1)}\n",
  359. "$$\n"
  360. ]
  361. },
  362. {
  363. "cell_type": "markdown",
  364. "metadata": {},
  365. "source": [
  366. "在 PyTorch 中,如果要调用自动求导,需要往`backward()`中传入一个参数,这个参数的形状和 n 一样大,比如是 $(w_0,\\ w_1)$,那么自动求导的结果就是:\n",
  367. "$$\n",
  368. "\\frac{\\partial n}{\\partial m_0} = w_0 \\frac{\\partial n_0}{\\partial m_0} + w_1 \\frac{\\partial n_1}{\\partial m_0}\n",
  369. "$$\n",
  370. "$$\n",
  371. "\\frac{\\partial n}{\\partial m_1} = w_0 \\frac{\\partial n_0}{\\partial m_1} + w_1 \\frac{\\partial n_1}{\\partial m_1}\n",
  372. "$$"
  373. ]
  374. },
  375. {
  376. "cell_type": "code",
  377. "execution_count": 14,
  378. "metadata": {},
  379. "outputs": [],
  380. "source": [
  381. "n.backward(torch.ones_like(n)) # 将 (w0, w1) 取成 (1, 1)"
  382. ]
  383. },
  384. {
  385. "cell_type": "code",
  386. "execution_count": 15,
  387. "metadata": {},
  388. "outputs": [
  389. {
  390. "name": "stdout",
  391. "output_type": "stream",
  392. "text": [
  393. "tensor([[ 4., 27.]])\n"
  394. ]
  395. }
  396. ],
  397. "source": [
  398. "print(m.grad)"
  399. ]
  400. },
  401. {
  402. "cell_type": "markdown",
  403. "metadata": {},
  404. "source": [
  405. "通过自动求导我们得到了梯度是 4 和 27,我们可以验算一下\n",
  406. "$$\n",
  407. "\\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\n",
  408. "$$\n",
  409. "$$\n",
  410. "\\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\n",
  411. "$$\n",
  412. "通过验算我们可以得到相同的结果"
  413. ]
  414. },
  415. {
  416. "cell_type": "markdown",
  417. "metadata": {},
  418. "source": [
  419. "\n"
  420. ]
  421. },
  422. {
  423. "cell_type": "markdown",
  424. "metadata": {},
  425. "source": [
  426. "## 多次自动求导\n",
  427. "通过调用 backward 我们可以进行一次自动求导,如果我们再调用一次 backward,会发现程序报错,没有办法再做一次。这是因为 PyTorch 默认做完一次自动求导之后,计算图就被丢弃了,所以两次自动求导需要手动设置一个东西,我们通过下面的小例子来说明。"
  428. ]
  429. },
  430. {
  431. "cell_type": "code",
  432. "execution_count": 20,
  433. "metadata": {},
  434. "outputs": [
  435. {
  436. "name": "stdout",
  437. "output_type": "stream",
  438. "text": [
  439. "tensor([18.], grad_fn=<AddBackward0>)\n"
  440. ]
  441. }
  442. ],
  443. "source": [
  444. "x = Variable(torch.FloatTensor([3]), requires_grad=True)\n",
  445. "y = x * 2 + x ** 2 + 3\n",
  446. "print(y)"
  447. ]
  448. },
  449. {
  450. "cell_type": "code",
  451. "execution_count": 21,
  452. "metadata": {},
  453. "outputs": [],
  454. "source": [
  455. "y.backward(retain_graph=True) # 设置 retain_graph 为 True 来保留计算图"
  456. ]
  457. },
  458. {
  459. "cell_type": "code",
  460. "execution_count": 22,
  461. "metadata": {},
  462. "outputs": [
  463. {
  464. "name": "stdout",
  465. "output_type": "stream",
  466. "text": [
  467. "tensor([8.])\n"
  468. ]
  469. }
  470. ],
  471. "source": [
  472. "print(x.grad)"
  473. ]
  474. },
  475. {
  476. "cell_type": "code",
  477. "execution_count": 23,
  478. "metadata": {},
  479. "outputs": [],
  480. "source": [
  481. "y.backward() # 再做一次自动求导,这次不保留计算图"
  482. ]
  483. },
  484. {
  485. "cell_type": "code",
  486. "execution_count": 24,
  487. "metadata": {},
  488. "outputs": [
  489. {
  490. "name": "stdout",
  491. "output_type": "stream",
  492. "text": [
  493. "tensor([16.])\n"
  494. ]
  495. }
  496. ],
  497. "source": [
  498. "print(x.grad)"
  499. ]
  500. },
  501. {
  502. "cell_type": "markdown",
  503. "metadata": {},
  504. "source": [
  505. "可以发现 x 的梯度变成了 16,因为这里做了两次自动求导,所以讲第一次的梯度 8 和第二次的梯度 8 加起来得到了 16 的结果。"
  506. ]
  507. },
  508. {
  509. "cell_type": "markdown",
  510. "metadata": {},
  511. "source": [
  512. "\n"
  513. ]
  514. },
  515. {
  516. "cell_type": "markdown",
  517. "metadata": {},
  518. "source": [
  519. "**小练习**\n",
  520. "\n",
  521. "定义\n",
  522. "\n",
  523. "$$\n",
  524. "x = \n",
  525. "\\left[\n",
  526. "\\begin{matrix}\n",
  527. "x_0 \\\\\n",
  528. "x_1\n",
  529. "\\end{matrix}\n",
  530. "\\right] = \n",
  531. "\\left[\n",
  532. "\\begin{matrix}\n",
  533. "2 \\\\\n",
  534. "3\n",
  535. "\\end{matrix}\n",
  536. "\\right]\n",
  537. "$$\n",
  538. "\n",
  539. "$$\n",
  540. "k = (k_0,\\ k_1) = (x_0^2 + 3 x_1,\\ 2 x_0 + x_1^2)\n",
  541. "$$\n",
  542. "\n",
  543. "我们希望求得\n",
  544. "\n",
  545. "$$\n",
  546. "j = \\left[\n",
  547. "\\begin{matrix}\n",
  548. "\\frac{\\partial k_0}{\\partial x_0} & \\frac{\\partial k_0}{\\partial x_1} \\\\\n",
  549. "\\frac{\\partial k_1}{\\partial x_0} & \\frac{\\partial k_1}{\\partial x_1}\n",
  550. "\\end{matrix}\n",
  551. "\\right]\n",
  552. "$$\n",
  553. "\n",
  554. "参考答案:\n",
  555. "\n",
  556. "$$\n",
  557. "\\left[\n",
  558. "\\begin{matrix}\n",
  559. "4 & 3 \\\\\n",
  560. "2 & 6 \\\\\n",
  561. "\\end{matrix}\n",
  562. "\\right]\n",
  563. "$$"
  564. ]
  565. },
  566. {
  567. "cell_type": "code",
  568. "execution_count": 29,
  569. "metadata": {},
  570. "outputs": [],
  571. "source": [
  572. "x = Variable(torch.FloatTensor([2, 3]), requires_grad=True)\n",
  573. "k = Variable(torch.zeros(2))\n",
  574. "\n",
  575. "k[0] = x[0] ** 2 + 3 * x[1]\n",
  576. "k[1] = x[1] ** 2 + 2 * x[0]"
  577. ]
  578. },
  579. {
  580. "cell_type": "code",
  581. "execution_count": 18,
  582. "metadata": {},
  583. "outputs": [],
  584. "source": [
  585. "#k.backward(torch.ones_like(k)) \n",
  586. "#print(x.grad)\n",
  587. "# 和上一个的区别在于该算法是求得导数和,并不是分布求解。"
  588. ]
  589. },
  590. {
  591. "cell_type": "code",
  592. "execution_count": 30,
  593. "metadata": {},
  594. "outputs": [
  595. {
  596. "name": "stdout",
  597. "output_type": "stream",
  598. "text": [
  599. "tensor([13., 13.], grad_fn=<CopySlices>)\n",
  600. "tensor([4., 3.])\n",
  601. "tensor([2., 6.])\n"
  602. ]
  603. }
  604. ],
  605. "source": [
  606. "j = torch.zeros(2, 2)\n",
  607. "k.backward(torch.FloatTensor([1, 0]), retain_graph=True)\n",
  608. "print(k)\n",
  609. "j[0] = x.grad.data\n",
  610. "print(x.grad.data)\n",
  611. "\n",
  612. "x.grad.data.zero_() # 归零之前求得的梯度\n",
  613. "\n",
  614. "k.backward(torch.FloatTensor([0, 1]))\n",
  615. "j[1] = x.grad.data\n",
  616. "print(x.grad.data)\n"
  617. ]
  618. },
  619. {
  620. "cell_type": "code",
  621. "execution_count": 31,
  622. "metadata": {},
  623. "outputs": [
  624. {
  625. "name": "stdout",
  626. "output_type": "stream",
  627. "text": [
  628. "tensor([13., 13.], grad_fn=<CopySlices>)\n"
  629. ]
  630. }
  631. ],
  632. "source": [
  633. "print(k)"
  634. ]
  635. },
  636. {
  637. "cell_type": "code",
  638. "execution_count": 32,
  639. "metadata": {},
  640. "outputs": [
  641. {
  642. "name": "stdout",
  643. "output_type": "stream",
  644. "text": [
  645. "tensor([[4., 3.],\n",
  646. " [2., 6.]])\n"
  647. ]
  648. }
  649. ],
  650. "source": [
  651. "print(j)"
  652. ]
  653. },
  654. {
  655. "cell_type": "markdown",
  656. "metadata": {},
  657. "source": [
  658. "下一次课我们会介绍两种神经网络的编程方式,动态图编程和静态图编程"
  659. ]
  660. }
  661. ],
  662. "metadata": {
  663. "kernelspec": {
  664. "display_name": "Python 3",
  665. "language": "python",
  666. "name": "python3"
  667. },
  668. "language_info": {
  669. "codemirror_mode": {
  670. "name": "ipython",
  671. "version": 3
  672. },
  673. "file_extension": ".py",
  674. "mimetype": "text/x-python",
  675. "name": "python",
  676. "nbconvert_exporter": "python",
  677. "pygments_lexer": "ipython3",
  678. "version": "3.6.9"
  679. }
  680. },
  681. "nbformat": 4,
  682. "nbformat_minor": 2
  683. }

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