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-batch-normalization.ipynb 22 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. {
  2. "cells": [
  3. {
  4. "cell_type": "markdown",
  5. "metadata": {},
  6. "source": [
  7. "# 批标准化\n",
  8. "在我们正式进入模型的构建和训练之前,我们会先讲一讲数据预处理和批标准化,因为模型训练并不容易,特别是一些非常复杂的模型,并不能非常好的训练得到收敛的结果,所以对数据增加一些预处理,同时使用批标准化能够得到非常好的收敛结果,这也是卷积网络能够训练到非常深的层的一个重要原因。"
  9. ]
  10. },
  11. {
  12. "cell_type": "markdown",
  13. "metadata": {},
  14. "source": [
  15. "## 数据预处理\n",
  16. "目前数据预处理最常见的方法就是中心化和标准化\n",
  17. "* 中心化相当于修正数据的中心位置,实现方法非常简单,就是在每个特征维度上减去对应的均值,最后得到 0 均值的特征。\n",
  18. "* 标准化也非常简单,在数据变成 0 均值之后,为了使得不同的特征维度有着相同的规模,可以除以标准差近似为一个标准正态分布,也可以依据最大值和最小值将其转化为 -1 ~ 1 之间\n",
  19. "\n",
  20. "下图是处理的的示例:\n",
  21. "\n",
  22. "![](images/data_normalize.png)\n",
  23. "\n"
  24. ]
  25. },
  26. {
  27. "cell_type": "markdown",
  28. "metadata": {},
  29. "source": [
  30. "## Batch Normalization\n",
  31. "前面在数据预处理的时候,我们尽量输入特征不相关且满足一个标准的正态分布,这样模型的表现一般也较好。但是对于很深的网路结构,网路的非线性层会使得输出的结果变得相关,且不再满足一个标准的 N(0, 1) 的分布,甚至输出的中心已经发生了偏移,这对于模型的训练,特别是深层的模型训练非常的困难。\n",
  32. "\n",
  33. "所以在 2015 年一篇论文提出了这个方法,批标准化,简而言之,就是对于每一层网络的输出,对其做一个归一化,使其服从标准的正态分布,这样后一层网络的输入也是一个标准的正态分布,所以能够比较好的进行训练,加快收敛速度。"
  34. ]
  35. },
  36. {
  37. "cell_type": "markdown",
  38. "metadata": {},
  39. "source": [
  40. "batch normalization 的实现非常简单,对于给定的一个 batch 的数据 $B = \\{x_1, x_2, \\cdots, x_m\\}$算法的公式如下\n",
  41. "\n",
  42. "$$\n",
  43. "\\mu_B = \\frac{1}{m} \\sum_{i=1}^m x_i\n",
  44. "$$\n",
  45. "$$\n",
  46. "\\sigma^2_B = \\frac{1}{m} \\sum_{i=1}^m (x_i - \\mu_B)^2\n",
  47. "$$\n",
  48. "$$\n",
  49. "\\hat{x}_i = \\frac{x_i - \\mu_B}{\\sqrt{\\sigma^2_B + \\epsilon}}\n",
  50. "$$\n",
  51. "$$\n",
  52. "y_i = \\gamma \\hat{x}_i + \\beta\n",
  53. "$$"
  54. ]
  55. },
  56. {
  57. "cell_type": "markdown",
  58. "metadata": {},
  59. "source": [
  60. "第一行和第二行是计算出一个 batch 中数据的均值和方差,接着使用第三个公式对 batch 中的每个数据点做标准化,$\\epsilon$ 是为了计算稳定引入的一个小的常数,通常取 $10^{-5}$,最后利用权重修正得到最后的输出结果,非常的简单,下面我们可以实现一下简单的一维的情况,也就是神经网络中的情况"
  61. ]
  62. },
  63. {
  64. "cell_type": "code",
  65. "execution_count": 1,
  66. "metadata": {
  67. "ExecuteTime": {
  68. "end_time": "2017-12-23T06:50:51.579067Z",
  69. "start_time": "2017-12-23T06:50:51.575693Z"
  70. }
  71. },
  72. "outputs": [],
  73. "source": [
  74. "import sys\n",
  75. "sys.path.append('..')\n",
  76. "\n",
  77. "import torch"
  78. ]
  79. },
  80. {
  81. "cell_type": "code",
  82. "execution_count": 2,
  83. "metadata": {
  84. "ExecuteTime": {
  85. "end_time": "2017-12-23T07:14:11.077807Z",
  86. "start_time": "2017-12-23T07:14:11.060849Z"
  87. }
  88. },
  89. "outputs": [],
  90. "source": [
  91. "def simple_batch_norm_1d(x, gamma, beta):\n",
  92. " eps = 1e-5\n",
  93. " x_mean = torch.mean(x, dim=0, keepdim=True) # 保留维度进行 broadcast\n",
  94. " x_var = torch.mean((x - x_mean) ** 2, dim=0, keepdim=True)\n",
  95. " x_hat = (x - x_mean) / torch.sqrt(x_var + eps)\n",
  96. " return gamma.view_as(x_mean) * x_hat + beta.view_as(x_mean)"
  97. ]
  98. },
  99. {
  100. "cell_type": "markdown",
  101. "metadata": {},
  102. "source": [
  103. "我们来验证一下是否对于任意的输入,输出会被标准化"
  104. ]
  105. },
  106. {
  107. "cell_type": "code",
  108. "execution_count": 3,
  109. "metadata": {
  110. "ExecuteTime": {
  111. "end_time": "2017-12-23T07:14:20.610603Z",
  112. "start_time": "2017-12-23T07:14:20.597682Z"
  113. }
  114. },
  115. "outputs": [
  116. {
  117. "name": "stdout",
  118. "output_type": "stream",
  119. "text": [
  120. "before bn: \n",
  121. "\n",
  122. " 0 1 2\n",
  123. " 3 4 5\n",
  124. " 6 7 8\n",
  125. " 9 10 11\n",
  126. " 12 13 14\n",
  127. "[torch.FloatTensor of size 5x3]\n",
  128. "\n",
  129. "after bn: \n",
  130. "\n",
  131. "-1.4142 -1.4142 -1.4142\n",
  132. "-0.7071 -0.7071 -0.7071\n",
  133. " 0.0000 0.0000 0.0000\n",
  134. " 0.7071 0.7071 0.7071\n",
  135. " 1.4142 1.4142 1.4142\n",
  136. "[torch.FloatTensor of size 5x3]\n",
  137. "\n"
  138. ]
  139. }
  140. ],
  141. "source": [
  142. "x = torch.arange(15).view(5, 3)\n",
  143. "gamma = torch.ones(x.shape[1])\n",
  144. "beta = torch.zeros(x.shape[1])\n",
  145. "print('before bn: ')\n",
  146. "print(x)\n",
  147. "y = simple_batch_norm_1d(x, gamma, beta)\n",
  148. "print('after bn: ')\n",
  149. "print(y)"
  150. ]
  151. },
  152. {
  153. "cell_type": "markdown",
  154. "metadata": {},
  155. "source": [
  156. "可以看到这里一共是 5 个数据点,三个特征,每一列表示一个特征的不同数据点,使用批标准化之后,每一列都变成了标准的正态分布\n",
  157. "\n",
  158. "这个时候会出现一个问题,就是测试的时候该使用批标准化吗?\n",
  159. "\n",
  160. "答案是肯定的,因为训练的时候使用了,而测试的时候不使用肯定会导致结果出现偏差,但是测试的时候如果只有一个数据集,那么均值不就是这个值,方差为 0 吗?这显然是随机的,所以测试的时候不能用测试的数据集去算均值和方差,而是用训练的时候算出的移动平均均值和方差去代替\n",
  161. "\n",
  162. "下面我们实现以下能够区分训练状态和测试状态的批标准化方法"
  163. ]
  164. },
  165. {
  166. "cell_type": "code",
  167. "execution_count": 4,
  168. "metadata": {
  169. "ExecuteTime": {
  170. "end_time": "2017-12-23T07:32:48.025709Z",
  171. "start_time": "2017-12-23T07:32:48.005892Z"
  172. }
  173. },
  174. "outputs": [],
  175. "source": [
  176. "def batch_norm_1d(x, gamma, beta, is_training, moving_mean, moving_var, moving_momentum=0.1):\n",
  177. " eps = 1e-5\n",
  178. " x_mean = torch.mean(x, dim=0, keepdim=True) # 保留维度进行 broadcast\n",
  179. " x_var = torch.mean((x - x_mean) ** 2, dim=0, keepdim=True)\n",
  180. " if is_training:\n",
  181. " x_hat = (x - x_mean) / torch.sqrt(x_var + eps)\n",
  182. " moving_mean[:] = moving_momentum * moving_mean + (1. - moving_momentum) * x_mean\n",
  183. " moving_var[:] = moving_momentum * moving_var + (1. - moving_momentum) * x_var\n",
  184. " else:\n",
  185. " x_hat = (x - moving_mean) / torch.sqrt(moving_var + eps)\n",
  186. " return gamma.view_as(x_mean) * x_hat + beta.view_as(x_mean)"
  187. ]
  188. },
  189. {
  190. "cell_type": "markdown",
  191. "metadata": {},
  192. "source": [
  193. "下面我们使用上一节课将的深度神经网络分类 mnist 数据集的例子来试验一下批标准化是否有用"
  194. ]
  195. },
  196. {
  197. "cell_type": "code",
  198. "execution_count": 5,
  199. "metadata": {},
  200. "outputs": [],
  201. "source": [
  202. "import numpy as np\n",
  203. "from torchvision.datasets import mnist # 导入 pytorch 内置的 mnist 数据\n",
  204. "from torch.utils.data import DataLoader\n",
  205. "from torch import nn\n",
  206. "from torch.autograd import Variable"
  207. ]
  208. },
  209. {
  210. "cell_type": "code",
  211. "execution_count": 6,
  212. "metadata": {},
  213. "outputs": [],
  214. "source": [
  215. "# 使用内置函数下载 mnist 数据集\n",
  216. "train_set = mnist.MNIST('../../data/mnist', train=True)\n",
  217. "test_set = mnist.MNIST('../../data/mnist', train=False)\n",
  218. "\n",
  219. "def data_tf(x):\n",
  220. " x = np.array(x, dtype='float32') / 255\n",
  221. " x = (x - 0.5) / 0.5 # 数据预处理,标准化\n",
  222. " x = x.reshape((-1,)) # 拉平\n",
  223. " x = torch.from_numpy(x)\n",
  224. " return x\n",
  225. "\n",
  226. "train_set = mnist.MNIST('../../data/mnist', train=True, transform=data_tf, download=True) # 重新载入数据集,申明定义的数据变换\n",
  227. "test_set = mnist.MNIST('../../data/mnist', train=False, transform=data_tf, download=True)\n",
  228. "train_data = DataLoader(train_set, batch_size=64, shuffle=True)\n",
  229. "test_data = DataLoader(test_set, batch_size=128, shuffle=False)"
  230. ]
  231. },
  232. {
  233. "cell_type": "code",
  234. "execution_count": 7,
  235. "metadata": {},
  236. "outputs": [],
  237. "source": [
  238. "class multi_network(nn.Module):\n",
  239. " def __init__(self):\n",
  240. " super(multi_network, self).__init__()\n",
  241. " self.layer1 = nn.Linear(784, 100)\n",
  242. " self.relu = nn.ReLU(True)\n",
  243. " self.layer2 = nn.Linear(100, 10)\n",
  244. " \n",
  245. " self.gamma = nn.Parameter(torch.randn(100))\n",
  246. " self.beta = nn.Parameter(torch.randn(100))\n",
  247. " \n",
  248. " self.moving_mean = Variable(torch.zeros(100))\n",
  249. " self.moving_var = Variable(torch.zeros(100))\n",
  250. " \n",
  251. " def forward(self, x, is_train=True):\n",
  252. " x = self.layer1(x)\n",
  253. " x = batch_norm_1d(x, self.gamma, self.beta, is_train, self.moving_mean, self.moving_var)\n",
  254. " x = self.relu(x)\n",
  255. " x = self.layer2(x)\n",
  256. " return x"
  257. ]
  258. },
  259. {
  260. "cell_type": "code",
  261. "execution_count": 8,
  262. "metadata": {},
  263. "outputs": [],
  264. "source": [
  265. "net = multi_network()"
  266. ]
  267. },
  268. {
  269. "cell_type": "code",
  270. "execution_count": 9,
  271. "metadata": {},
  272. "outputs": [],
  273. "source": [
  274. "# 定义 loss 函数\n",
  275. "criterion = nn.CrossEntropyLoss()\n",
  276. "optimizer = torch.optim.SGD(net.parameters(), 1e-1) # 使用随机梯度下降,学习率 0.1"
  277. ]
  278. },
  279. {
  280. "cell_type": "markdown",
  281. "metadata": {},
  282. "source": [
  283. "为了方便,训练函数已经定义在外面的 utils.py 中,跟前面训练网络的操作是一样的,感兴趣的同学可以去看看"
  284. ]
  285. },
  286. {
  287. "cell_type": "code",
  288. "execution_count": 10,
  289. "metadata": {},
  290. "outputs": [
  291. {
  292. "name": "stdout",
  293. "output_type": "stream",
  294. "text": [
  295. "Epoch 0. Train Loss: 0.308139, Train Acc: 0.912797, Valid Loss: 0.181375, Valid Acc: 0.948279, Time 00:00:07\n",
  296. "Epoch 1. Train Loss: 0.174049, Train Acc: 0.949910, Valid Loss: 0.143940, Valid Acc: 0.958267, Time 00:00:09\n",
  297. "Epoch 2. Train Loss: 0.134983, Train Acc: 0.961587, Valid Loss: 0.122489, Valid Acc: 0.963904, Time 00:00:08\n",
  298. "Epoch 3. Train Loss: 0.111758, Train Acc: 0.968317, Valid Loss: 0.106595, Valid Acc: 0.966278, Time 00:00:09\n",
  299. "Epoch 4. Train Loss: 0.096425, Train Acc: 0.971915, Valid Loss: 0.108423, Valid Acc: 0.967563, Time 00:00:10\n",
  300. "Epoch 5. Train Loss: 0.084424, Train Acc: 0.974464, Valid Loss: 0.107135, Valid Acc: 0.969838, Time 00:00:09\n",
  301. "Epoch 6. Train Loss: 0.076206, Train Acc: 0.977645, Valid Loss: 0.092725, Valid Acc: 0.971420, Time 00:00:09\n",
  302. "Epoch 7. Train Loss: 0.069438, Train Acc: 0.979661, Valid Loss: 0.091497, Valid Acc: 0.971519, Time 00:00:09\n",
  303. "Epoch 8. Train Loss: 0.062908, Train Acc: 0.980810, Valid Loss: 0.088797, Valid Acc: 0.972903, Time 00:00:08\n",
  304. "Epoch 9. Train Loss: 0.058186, Train Acc: 0.982309, Valid Loss: 0.090830, Valid Acc: 0.972310, Time 00:00:08\n"
  305. ]
  306. }
  307. ],
  308. "source": [
  309. "from utils import train\n",
  310. "train(net, train_data, test_data, 10, optimizer, criterion)"
  311. ]
  312. },
  313. {
  314. "cell_type": "markdown",
  315. "metadata": {},
  316. "source": [
  317. "这里的 $\\gamma$ 和 $\\beta$ 都作为参数进行训练,初始化为随机的高斯分布,`moving_mean` 和 `moving_var` 都初始化为 0,并不是更新的参数,训练完 10 次之后,我们可以看看移动平均和移动方差被修改为了多少"
  318. ]
  319. },
  320. {
  321. "cell_type": "code",
  322. "execution_count": 11,
  323. "metadata": {
  324. "scrolled": true
  325. },
  326. "outputs": [
  327. {
  328. "name": "stdout",
  329. "output_type": "stream",
  330. "text": [
  331. "Variable containing:\n",
  332. " 0.5505\n",
  333. " 2.0835\n",
  334. " 0.0794\n",
  335. "-0.1991\n",
  336. "-0.9822\n",
  337. "-0.5820\n",
  338. " 0.6991\n",
  339. "-0.1292\n",
  340. " 2.9608\n",
  341. " 1.0826\n",
  342. "[torch.FloatTensor of size 10]\n",
  343. "\n"
  344. ]
  345. }
  346. ],
  347. "source": [
  348. "# 打出 moving_mean 的前 10 项\n",
  349. "print(net.moving_mean[:10])"
  350. ]
  351. },
  352. {
  353. "cell_type": "markdown",
  354. "metadata": {},
  355. "source": [
  356. "可以看到,这些值已经在训练的过程中进行了修改,在测试过程中,我们不需要再计算均值和方差,直接使用移动平均和移动方差即可"
  357. ]
  358. },
  359. {
  360. "cell_type": "markdown",
  361. "metadata": {},
  362. "source": [
  363. "作为对比,我们看看不使用批标准化的结果"
  364. ]
  365. },
  366. {
  367. "cell_type": "code",
  368. "execution_count": 12,
  369. "metadata": {},
  370. "outputs": [
  371. {
  372. "name": "stdout",
  373. "output_type": "stream",
  374. "text": [
  375. "Epoch 0. Train Loss: 0.402263, Train Acc: 0.873817, Valid Loss: 0.220468, Valid Acc: 0.932852, Time 00:00:07\n",
  376. "Epoch 1. Train Loss: 0.181916, Train Acc: 0.945379, Valid Loss: 0.162440, Valid Acc: 0.953817, Time 00:00:08\n",
  377. "Epoch 2. Train Loss: 0.136073, Train Acc: 0.958522, Valid Loss: 0.264888, Valid Acc: 0.918216, Time 00:00:08\n",
  378. "Epoch 3. Train Loss: 0.111658, Train Acc: 0.966551, Valid Loss: 0.149704, Valid Acc: 0.950752, Time 00:00:08\n",
  379. "Epoch 4. Train Loss: 0.096433, Train Acc: 0.970732, Valid Loss: 0.116364, Valid Acc: 0.963311, Time 00:00:07\n",
  380. "Epoch 5. Train Loss: 0.083800, Train Acc: 0.973914, Valid Loss: 0.105775, Valid Acc: 0.968058, Time 00:00:08\n",
  381. "Epoch 6. Train Loss: 0.074534, Train Acc: 0.977129, Valid Loss: 0.094511, Valid Acc: 0.970728, Time 00:00:08\n",
  382. "Epoch 7. Train Loss: 0.067365, Train Acc: 0.979311, Valid Loss: 0.130495, Valid Acc: 0.960146, Time 00:00:09\n",
  383. "Epoch 8. Train Loss: 0.061585, Train Acc: 0.980894, Valid Loss: 0.089632, Valid Acc: 0.974090, Time 00:00:08\n",
  384. "Epoch 9. Train Loss: 0.055352, Train Acc: 0.982892, Valid Loss: 0.091508, Valid Acc: 0.970431, Time 00:00:08\n"
  385. ]
  386. }
  387. ],
  388. "source": [
  389. "no_bn_net = nn.Sequential(\n",
  390. " nn.Linear(784, 100),\n",
  391. " nn.ReLU(True),\n",
  392. " nn.Linear(100, 10)\n",
  393. ")\n",
  394. "\n",
  395. "optimizer = torch.optim.SGD(no_bn_net.parameters(), 1e-1) # 使用随机梯度下降,学习率 0.1\n",
  396. "train(no_bn_net, train_data, test_data, 10, optimizer, criterion)"
  397. ]
  398. },
  399. {
  400. "cell_type": "markdown",
  401. "metadata": {},
  402. "source": [
  403. "可以看到虽然最后的结果两种情况一样,但是如果我们看前几次的情况,可以看到使用批标准化的情况能够更快的收敛,因为这只是一个小网络,所以用不用批标准化都能够收敛,但是对于更加深的网络,使用批标准化在训练的时候能够很快地收敛"
  404. ]
  405. },
  406. {
  407. "cell_type": "markdown",
  408. "metadata": {},
  409. "source": [
  410. "从上面可以看到,我们自己实现了 2 维情况的批标准化,对应于卷积的 4 维情况的标准化是类似的,只需要沿着通道的维度进行均值和方差的计算,但是我们自己实现批标准化是很累的,pytorch 当然也为我们内置了批标准化的函数,一维和二维分别是 `torch.nn.BatchNorm1d()` 和 `torch.nn.BatchNorm2d()`,不同于我们的实现,pytorch 不仅将 $\\gamma$ 和 $\\beta$ 作为训练的参数,也将 `moving_mean` 和 `moving_var` 也作为参数进行训练"
  411. ]
  412. },
  413. {
  414. "cell_type": "markdown",
  415. "metadata": {},
  416. "source": [
  417. "下面我们在卷积网络下试用一下批标准化看看效果"
  418. ]
  419. },
  420. {
  421. "cell_type": "code",
  422. "execution_count": null,
  423. "metadata": {},
  424. "outputs": [],
  425. "source": [
  426. "def data_tf(x):\n",
  427. " x = np.array(x, dtype='float32') / 255\n",
  428. " x = (x - 0.5) / 0.5 # 数据预处理,标准化\n",
  429. " x = torch.from_numpy(x)\n",
  430. " x = x.unsqueeze(0)\n",
  431. " return x\n",
  432. "\n",
  433. "train_set = mnist.MNIST('../../data/mnist', train=True, transform=data_tf, download=True) # 重新载入数据集,申明定义的数据变换\n",
  434. "test_set = mnist.MNIST('../../data/mnist', train=False, transform=data_tf, download=True)\n",
  435. "train_data = DataLoader(train_set, batch_size=64, shuffle=True)\n",
  436. "test_data = DataLoader(test_set, batch_size=128, shuffle=False)"
  437. ]
  438. },
  439. {
  440. "cell_type": "code",
  441. "execution_count": 78,
  442. "metadata": {},
  443. "outputs": [],
  444. "source": [
  445. "# 使用批标准化\n",
  446. "class conv_bn_net(nn.Module):\n",
  447. " def __init__(self):\n",
  448. " super(conv_bn_net, self).__init__()\n",
  449. " self.stage1 = nn.Sequential(\n",
  450. " nn.Conv2d(1, 6, 3, padding=1),\n",
  451. " nn.BatchNorm2d(6),\n",
  452. " nn.ReLU(True),\n",
  453. " nn.MaxPool2d(2, 2),\n",
  454. " nn.Conv2d(6, 16, 5),\n",
  455. " nn.BatchNorm2d(16),\n",
  456. " nn.ReLU(True),\n",
  457. " nn.MaxPool2d(2, 2)\n",
  458. " )\n",
  459. " \n",
  460. " self.classfy = nn.Linear(400, 10)\n",
  461. " def forward(self, x):\n",
  462. " x = self.stage1(x)\n",
  463. " x = x.view(x.shape[0], -1)\n",
  464. " x = self.classfy(x)\n",
  465. " return x\n",
  466. "\n",
  467. "net = conv_bn_net()\n",
  468. "optimizer = torch.optim.SGD(net.parameters(), 1e-1) # 使用随机梯度下降,学习率 0.1"
  469. ]
  470. },
  471. {
  472. "cell_type": "code",
  473. "execution_count": 79,
  474. "metadata": {},
  475. "outputs": [
  476. {
  477. "name": "stdout",
  478. "output_type": "stream",
  479. "text": [
  480. "Epoch 0. Train Loss: 0.160329, Train Acc: 0.952842, Valid Loss: 0.063328, Valid Acc: 0.978441, Time 00:00:33\n",
  481. "Epoch 1. Train Loss: 0.067862, Train Acc: 0.979361, Valid Loss: 0.068229, Valid Acc: 0.979430, Time 00:00:37\n",
  482. "Epoch 2. Train Loss: 0.051867, Train Acc: 0.984625, Valid Loss: 0.044616, Valid Acc: 0.985265, Time 00:00:37\n",
  483. "Epoch 3. Train Loss: 0.044797, Train Acc: 0.986141, Valid Loss: 0.042711, Valid Acc: 0.986056, Time 00:00:38\n",
  484. "Epoch 4. Train Loss: 0.039876, Train Acc: 0.987690, Valid Loss: 0.042499, Valid Acc: 0.985067, Time 00:00:41\n"
  485. ]
  486. }
  487. ],
  488. "source": [
  489. "train(net, train_data, test_data, 5, optimizer, criterion)"
  490. ]
  491. },
  492. {
  493. "cell_type": "code",
  494. "execution_count": 76,
  495. "metadata": {},
  496. "outputs": [],
  497. "source": [
  498. "# 不使用批标准化\n",
  499. "class conv_no_bn_net(nn.Module):\n",
  500. " def __init__(self):\n",
  501. " super(conv_no_bn_net, self).__init__()\n",
  502. " self.stage1 = nn.Sequential(\n",
  503. " nn.Conv2d(1, 6, 3, padding=1),\n",
  504. " nn.ReLU(True),\n",
  505. " nn.MaxPool2d(2, 2),\n",
  506. " nn.Conv2d(6, 16, 5),\n",
  507. " nn.ReLU(True),\n",
  508. " nn.MaxPool2d(2, 2)\n",
  509. " )\n",
  510. " \n",
  511. " self.classfy = nn.Linear(400, 10)\n",
  512. " def forward(self, x):\n",
  513. " x = self.stage1(x)\n",
  514. " x = x.view(x.shape[0], -1)\n",
  515. " x = self.classfy(x)\n",
  516. " return x\n",
  517. "\n",
  518. "net = conv_no_bn_net()\n",
  519. "optimizer = torch.optim.SGD(net.parameters(), 1e-1) # 使用随机梯度下降,学习率 0.1 "
  520. ]
  521. },
  522. {
  523. "cell_type": "code",
  524. "execution_count": 77,
  525. "metadata": {},
  526. "outputs": [
  527. {
  528. "name": "stdout",
  529. "output_type": "stream",
  530. "text": [
  531. "Epoch 0. Train Loss: 0.211075, Train Acc: 0.935934, Valid Loss: 0.062950, Valid Acc: 0.980123, Time 00:00:27\n",
  532. "Epoch 1. Train Loss: 0.066763, Train Acc: 0.978778, Valid Loss: 0.050143, Valid Acc: 0.984375, Time 00:00:29\n",
  533. "Epoch 2. Train Loss: 0.050870, Train Acc: 0.984292, Valid Loss: 0.039761, Valid Acc: 0.988034, Time 00:00:29\n",
  534. "Epoch 3. Train Loss: 0.041476, Train Acc: 0.986924, Valid Loss: 0.041925, Valid Acc: 0.986155, Time 00:00:29\n",
  535. "Epoch 4. Train Loss: 0.036118, Train Acc: 0.988523, Valid Loss: 0.042703, Valid Acc: 0.986452, Time 00:00:29\n"
  536. ]
  537. }
  538. ],
  539. "source": [
  540. "train(net, train_data, test_data, 5, optimizer, criterion)"
  541. ]
  542. },
  543. {
  544. "cell_type": "markdown",
  545. "metadata": {},
  546. "source": [
  547. "之后介绍一些著名的网络结构的时候,我们会慢慢认识到批标准化的重要性,使用 pytorch 能够非常方便地添加批标准化层"
  548. ]
  549. },
  550. {
  551. "cell_type": "markdown",
  552. "metadata": {},
  553. "source": [
  554. "## References\n",
  555. "* [透彻分析批归一化Batch Normalization强大作用](https://m.toutiaocdn.com/i6641764088760238595)"
  556. ]
  557. }
  558. ],
  559. "metadata": {
  560. "kernelspec": {
  561. "display_name": "Python 3",
  562. "language": "python",
  563. "name": "python3"
  564. },
  565. "language_info": {
  566. "codemirror_mode": {
  567. "name": "ipython",
  568. "version": 3
  569. },
  570. "file_extension": ".py",
  571. "mimetype": "text/x-python",
  572. "name": "python",
  573. "nbconvert_exporter": "python",
  574. "pygments_lexer": "ipython3",
  575. "version": "3.7.9"
  576. }
  577. },
  578. "nbformat": 4,
  579. "nbformat_minor": 2
  580. }

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