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

394 lines
13 KiB

  1. {
  2. "cells": [
  3. {
  4. "cell_type": "code",
  5. "execution_count": null,
  6. "metadata": {},
  7. "outputs": [],
  8. "source": [
  9. "from google.colab import drive\n",
  10. "\n",
  11. "drive.mount('/content/drive', force_remount=True)\n",
  12. "\n",
  13. "# 输入daseCV所在的路径\n",
  14. "# 'daseCV' 文件夹包括 '.py', 'classifiers' 和'datasets'文件夹\n",
  15. "# 例如 'CV/assignments/assignment1/daseCV/'\n",
  16. "FOLDERNAME = None\n",
  17. "\n",
  18. "assert FOLDERNAME is not None, \"[!] Enter the foldername.\"\n",
  19. "\n",
  20. "%cd drive/My\\ Drive\n",
  21. "%cp -r $FOLDERNAME ../../\n",
  22. "%cd ../../\n",
  23. "%cd daseCV/datasets/\n",
  24. "!bash get_datasets.sh\n",
  25. "%cd ../../"
  26. ]
  27. },
  28. {
  29. "cell_type": "markdown",
  30. "metadata": {
  31. "tags": [
  32. "pdf-title"
  33. ]
  34. },
  35. "source": [
  36. "# Softmax 练习\n",
  37. "\n",
  38. "*补充并完成本练习。*\n",
  39. "\n",
  40. "本练习类似于SVM练习,你要完成的事情包括:\n",
  41. "\n",
  42. "- 为Softmax分类器实现完全矢量化的**损失函数**\n",
  43. "- 实现其**解析梯度(analytic gradient)**的完全矢量化表达式\n",
  44. "- 用数值梯度**检查你的代码**\n",
  45. "- 使用验证集**调整学习率和正则化强度**\n",
  46. "- 使用**SGD优化**损失函数\n",
  47. "- **可视化**最终学习的权重\n"
  48. ]
  49. },
  50. {
  51. "cell_type": "code",
  52. "execution_count": null,
  53. "metadata": {
  54. "tags": [
  55. "pdf-ignore"
  56. ]
  57. },
  58. "outputs": [],
  59. "source": [
  60. "import random\n",
  61. "import numpy as np\n",
  62. "from daseCV.data_utils import load_CIFAR10\n",
  63. "import matplotlib.pyplot as plt\n",
  64. "\n",
  65. "%matplotlib inline\n",
  66. "plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots\n",
  67. "plt.rcParams['image.interpolation'] = 'nearest'\n",
  68. "plt.rcParams['image.cmap'] = 'gray'\n",
  69. "\n",
  70. "# for auto-reloading extenrnal modules\n",
  71. "# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n",
  72. "%load_ext autoreload\n",
  73. "%autoreload 2"
  74. ]
  75. },
  76. {
  77. "cell_type": "code",
  78. "execution_count": null,
  79. "metadata": {
  80. "tags": [
  81. "pdf-ignore"
  82. ]
  83. },
  84. "outputs": [],
  85. "source": [
  86. "def get_CIFAR10_data(num_training=49000, num_validation=1000, num_test=1000, num_dev=500):\n",
  87. " \"\"\"\n",
  88. " Load the CIFAR-10 dataset from disk and perform preprocessing to prepare\n",
  89. " it for the linear classifier. These are the same steps as we used for the\n",
  90. " SVM, but condensed to a single function. \n",
  91. " \"\"\"\n",
  92. " # Load the raw CIFAR-10 data\n",
  93. " cifar10_dir = 'daseCV/datasets/cifar-10-batches-py'\n",
  94. " \n",
  95. " # Cleaning up variables to prevent loading data multiple times (which may cause memory issue)\n",
  96. " try:\n",
  97. " del X_train, y_train\n",
  98. " del X_test, y_test\n",
  99. " print('Clear previously loaded data.')\n",
  100. " except:\n",
  101. " pass\n",
  102. "\n",
  103. " X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)\n",
  104. " \n",
  105. " # subsample the data\n",
  106. " mask = list(range(num_training, num_training + num_validation))\n",
  107. " X_val = X_train[mask]\n",
  108. " y_val = y_train[mask]\n",
  109. " mask = list(range(num_training))\n",
  110. " X_train = X_train[mask]\n",
  111. " y_train = y_train[mask]\n",
  112. " mask = list(range(num_test))\n",
  113. " X_test = X_test[mask]\n",
  114. " y_test = y_test[mask]\n",
  115. " mask = np.random.choice(num_training, num_dev, replace=False)\n",
  116. " X_dev = X_train[mask]\n",
  117. " y_dev = y_train[mask]\n",
  118. " \n",
  119. " # Preprocessing: reshape the image data into rows\n",
  120. " X_train = np.reshape(X_train, (X_train.shape[0], -1))\n",
  121. " X_val = np.reshape(X_val, (X_val.shape[0], -1))\n",
  122. " X_test = np.reshape(X_test, (X_test.shape[0], -1))\n",
  123. " X_dev = np.reshape(X_dev, (X_dev.shape[0], -1))\n",
  124. " \n",
  125. " # Normalize the data: subtract the mean image\n",
  126. " mean_image = np.mean(X_train, axis = 0)\n",
  127. " X_train -= mean_image\n",
  128. " X_val -= mean_image\n",
  129. " X_test -= mean_image\n",
  130. " X_dev -= mean_image\n",
  131. " \n",
  132. " # add bias dimension and transform into columns\n",
  133. " X_train = np.hstack([X_train, np.ones((X_train.shape[0], 1))])\n",
  134. " X_val = np.hstack([X_val, np.ones((X_val.shape[0], 1))])\n",
  135. " X_test = np.hstack([X_test, np.ones((X_test.shape[0], 1))])\n",
  136. " X_dev = np.hstack([X_dev, np.ones((X_dev.shape[0], 1))])\n",
  137. " \n",
  138. " return X_train, y_train, X_val, y_val, X_test, y_test, X_dev, y_dev\n",
  139. "\n",
  140. "\n",
  141. "# Invoke the above function to get our data.\n",
  142. "X_train, y_train, X_val, y_val, X_test, y_test, X_dev, y_dev = get_CIFAR10_data()\n",
  143. "print('Train data shape: ', X_train.shape)\n",
  144. "print('Train labels shape: ', y_train.shape)\n",
  145. "print('Validation data shape: ', X_val.shape)\n",
  146. "print('Validation labels shape: ', y_val.shape)\n",
  147. "print('Test data shape: ', X_test.shape)\n",
  148. "print('Test labels shape: ', y_test.shape)\n",
  149. "print('dev data shape: ', X_dev.shape)\n",
  150. "print('dev labels shape: ', y_dev.shape)"
  151. ]
  152. },
  153. {
  154. "cell_type": "markdown",
  155. "metadata": {},
  156. "source": [
  157. "## Softmax 分类器\n",
  158. "\n",
  159. "请在**daseCV/classifiers/softmax.py**中完成本节的代码。"
  160. ]
  161. },
  162. {
  163. "cell_type": "code",
  164. "execution_count": null,
  165. "metadata": {},
  166. "outputs": [],
  167. "source": [
  168. "# 首先使用嵌套循环实现简单的softmax损失函数。\n",
  169. "# 打开文件 daseCV/classifiers/softmax.py 并补充完成\n",
  170. "# softmax_loss_naive 函数.\n",
  171. "\n",
  172. "from daseCV.classifiers.softmax import softmax_loss_naive\n",
  173. "import time\n",
  174. "\n",
  175. "# 生成一个随机的softmax权重矩阵,并使用它来计算损失。\n",
  176. "W = np.random.randn(3073, 10) * 0.0001\n",
  177. "loss, grad = softmax_loss_naive(W, X_dev, y_dev, 0.0)\n",
  178. "\n",
  179. "# As a rough sanity check, our loss should be something close to -log(0.1).\n",
  180. "print('loss: %f' % loss)\n",
  181. "print('sanity check: %f' % (-np.log(0.1)))"
  182. ]
  183. },
  184. {
  185. "cell_type": "markdown",
  186. "metadata": {
  187. "tags": [
  188. "pdf-inline"
  189. ]
  190. },
  191. "source": [
  192. "**问题 1**\n",
  193. "\n",
  194. "\n",
  195. "为什么我们期望损失接近-log(0.1)?简要说明。\n",
  196. "\n",
  197. "$\\color{blue}{\\textit 答:}$ *在这里写上你的答案* \n",
  198. "\n"
  199. ]
  200. },
  201. {
  202. "cell_type": "code",
  203. "execution_count": null,
  204. "metadata": {},
  205. "outputs": [],
  206. "source": [
  207. "# 完成softmax_loss_naive,并实现使用嵌套循环的梯度的版本(naive)。\n",
  208. "loss, grad = softmax_loss_naive(W, X_dev, y_dev, 0.0)\n",
  209. "\n",
  210. "# 就像SVM那样,请使用数值梯度检查作为调试工具。\n",
  211. "# 数值梯度应接近分析梯度。\n",
  212. "from daseCV.gradient_check import grad_check_sparse\n",
  213. "f = lambda w: softmax_loss_naive(w, X_dev, y_dev, 0.0)[0]\n",
  214. "grad_numerical = grad_check_sparse(f, W, grad, 10)\n",
  215. "\n",
  216. "# 与SVM情况类似,使用正则化进行另一个梯度检查\n",
  217. "loss, grad = softmax_loss_naive(W, X_dev, y_dev, 5e1)\n",
  218. "f = lambda w: softmax_loss_naive(w, X_dev, y_dev, 5e1)[0]\n",
  219. "grad_numerical = grad_check_sparse(f, W, grad, 10)"
  220. ]
  221. },
  222. {
  223. "cell_type": "code",
  224. "execution_count": null,
  225. "metadata": {},
  226. "outputs": [],
  227. "source": [
  228. "# 现在,我们有了softmax损失函数及其梯度的简单实现,\n",
  229. "# 接下来要在 softmax_loss_vectorized 中完成一个向量化版本.\n",
  230. "# 这两个版本应计算出相同的结果,但矢量化版本应更快。\n",
  231. "tic = time.time()\n",
  232. "loss_naive, grad_naive = softmax_loss_naive(W, X_dev, y_dev, 0.000005)\n",
  233. "toc = time.time()\n",
  234. "print('naive loss: %e computed in %fs' % (loss_naive, toc - tic))\n",
  235. "\n",
  236. "from daseCV.classifiers.softmax import softmax_loss_vectorized\n",
  237. "tic = time.time()\n",
  238. "loss_vectorized, grad_vectorized = softmax_loss_vectorized(W, X_dev, y_dev, 0.000005)\n",
  239. "toc = time.time()\n",
  240. "print('vectorized loss: %e computed in %fs' % (loss_vectorized, toc - tic))\n",
  241. "\n",
  242. "# 正如前面在SVM练习中所做的一样,我们使用Frobenius范数比较两个版本梯度。\n",
  243. "grad_difference = np.linalg.norm(grad_naive - grad_vectorized, ord='fro')\n",
  244. "print('Loss difference: %f' % np.abs(loss_naive - loss_vectorized))\n",
  245. "print('Gradient difference: %f' % grad_difference)"
  246. ]
  247. },
  248. {
  249. "cell_type": "code",
  250. "execution_count": null,
  251. "metadata": {
  252. "tags": [
  253. "code"
  254. ]
  255. },
  256. "outputs": [],
  257. "source": [
  258. "# 使用验证集调整超参数(正则化强度和学习率)。您应该尝试不同的学习率和正则化强度范围; \n",
  259. "# 如果您小心的话,您应该能够在验证集上获得超过0.35的精度。\n",
  260. "from daseCV.classifiers import Softmax\n",
  261. "results = {}\n",
  262. "best_val = -1\n",
  263. "best_softmax = None\n",
  264. "learning_rates = [1e-7, 5e-7]\n",
  265. "regularization_strengths = [2.5e4, 5e4]\n",
  266. "\n",
  267. "################################################################################\n",
  268. "# 需要完成的事: \n",
  269. "# 对验证集设置学习率和正则化强度。\n",
  270. "# 这与之前SVM中做的类似;\n",
  271. "# 保存训练效果最好的softmax分类器到best_softmax中。\n",
  272. "################################################################################\n",
  273. "# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****\n",
  274. "\n",
  275. "pass\n",
  276. "\n",
  277. "# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****\n",
  278. " \n",
  279. "# Print out results.\n",
  280. "for lr, reg in sorted(results):\n",
  281. " train_accuracy, val_accuracy = results[(lr, reg)]\n",
  282. " print('lr %e reg %e train accuracy: %f val accuracy: %f' % (\n",
  283. " lr, reg, train_accuracy, val_accuracy))\n",
  284. " \n",
  285. "print('best validation accuracy achieved during cross-validation: %f' % best_val)"
  286. ]
  287. },
  288. {
  289. "cell_type": "code",
  290. "execution_count": null,
  291. "metadata": {},
  292. "outputs": [],
  293. "source": [
  294. "# 在测试集上评估\n",
  295. "# 在测试集上评估最好的softmax\n",
  296. "y_test_pred = best_softmax.predict(X_test)\n",
  297. "test_accuracy = np.mean(y_test == y_test_pred)\n",
  298. "print('softmax on raw pixels final test set accuracy: %f' % (test_accuracy, ))"
  299. ]
  300. },
  301. {
  302. "cell_type": "markdown",
  303. "metadata": {
  304. "tags": [
  305. "pdf-inline"
  306. ]
  307. },
  308. "source": [
  309. "**问题 2** - *对或错*\n",
  310. "\n",
  311. "假设总训练损失定义为所有训练样本中每个数据点损失的总和。可能会有新的数据点添加到训练集中,同时SVM损失保持不变,但是对于Softmax分类器的损失而言,情况并非如此。\n",
  312. "\n",
  313. "$\\color{blue}{\\textit 你的回答:}$\n",
  314. "\n",
  315. "\n",
  316. "$\\color{blue}{\\textit 你的解释:}$\n",
  317. "\n"
  318. ]
  319. },
  320. {
  321. "cell_type": "code",
  322. "execution_count": null,
  323. "metadata": {},
  324. "outputs": [],
  325. "source": [
  326. "# 可视化每个类别的学习到的权重\n",
  327. "w = best_softmax.W[:-1,:] # strip out the bias\n",
  328. "w = w.reshape(32, 32, 3, 10)\n",
  329. "\n",
  330. "w_min, w_max = np.min(w), np.max(w)\n",
  331. "\n",
  332. "classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']\n",
  333. "for i in range(10):\n",
  334. " plt.subplot(2, 5, i + 1)\n",
  335. " \n",
  336. " # Rescale the weights to be between 0 and 255\n",
  337. " wimg = 255.0 * (w[:, :, :, i].squeeze() - w_min) / (w_max - w_min)\n",
  338. " plt.imshow(wimg.astype('uint8'))\n",
  339. " plt.axis('off')\n",
  340. " plt.title(classes[i])"
  341. ]
  342. },
  343. {
  344. "cell_type": "markdown",
  345. "metadata": {},
  346. "source": [
  347. "---\n",
  348. "# 重要\n",
  349. "\n",
  350. "这里是作业的结尾处,请执行以下步骤:\n",
  351. "\n",
  352. "1. 点击`File -> Save`或者用`control+s`组合键,确保你最新的的notebook的作业已经保存到谷歌云。\n",
  353. "2. 执行以下代码确保 `.py` 文件保存回你的谷歌云。"
  354. ]
  355. },
  356. {
  357. "cell_type": "code",
  358. "execution_count": null,
  359. "metadata": {},
  360. "outputs": [],
  361. "source": [
  362. "import os\n",
  363. "\n",
  364. "FOLDER_TO_SAVE = os.path.join('drive/My Drive/', FOLDERNAME)\n",
  365. "FILES_TO_SAVE = ['daseCV/classifiers/softmax.py']\n",
  366. "\n",
  367. "for files in FILES_TO_SAVE:\n",
  368. " with open(os.path.join(FOLDER_TO_SAVE, '/'.join(files.split('/')[1:])), 'w') as f:\n",
  369. " f.write(''.join(open(files).readlines()))"
  370. ]
  371. }
  372. ],
  373. "metadata": {
  374. "kernelspec": {
  375. "display_name": "Python 3",
  376. "language": "python",
  377. "name": "python3"
  378. },
  379. "language_info": {
  380. "codemirror_mode": {
  381. "name": "ipython",
  382. "version": 3
  383. },
  384. "file_extension": ".py",
  385. "mimetype": "text/x-python",
  386. "name": "python",
  387. "nbconvert_exporter": "python",
  388. "pygments_lexer": "ipython3",
  389. "version": "3.7.0"
  390. }
  391. },
  392. "nbformat": 4,
  393. "nbformat_minor": 1
  394. }