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.

618 regels
20 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. "# 多分类支撑向量机练习\n",
  37. "*完成此练习并且上交本ipynb(包含输出及代码).*\n",
  38. "\n",
  39. "在这个练习中,你将会:\n",
  40. " \n",
  41. "- 为SVM构建一个完全向量化的**损失函数**\n",
  42. "- 实现**解析梯度**的向量化表达式\n",
  43. "- 使用数值梯度检查你的代码是否正确\n",
  44. "- 使用验证集**调整学习率和正则化项**\n",
  45. "- 用**SGD(随机梯度下降)** **优化**损失函数\n",
  46. "- **可视化** 最后学习到的权重\n"
  47. ]
  48. },
  49. {
  50. "cell_type": "code",
  51. "execution_count": null,
  52. "metadata": {
  53. "tags": [
  54. "pdf-ignore"
  55. ]
  56. },
  57. "outputs": [],
  58. "source": [
  59. "# 导入包\n",
  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. "# 下面一行是notebook的magic命令,作用是让matplotlib在notebook内绘图(而不是新建一个窗口)\n",
  66. "%matplotlib inline\n",
  67. "plt.rcParams['figure.figsize'] = (10.0, 8.0) # 设置绘图的默认大小\n",
  68. "plt.rcParams['image.interpolation'] = 'nearest'\n",
  69. "plt.rcParams['image.cmap'] = 'gray'\n",
  70. "\n",
  71. "# 该magic命令可以重载外部的python模块\n",
  72. "# 相关资料可以去看 http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n",
  73. "%load_ext autoreload\n",
  74. "%autoreload 2"
  75. ]
  76. },
  77. {
  78. "cell_type": "markdown",
  79. "metadata": {
  80. "tags": [
  81. "pdf-ignore"
  82. ]
  83. },
  84. "source": [
  85. "## 准备和预处理CIFAR-10的数据"
  86. ]
  87. },
  88. {
  89. "cell_type": "code",
  90. "execution_count": null,
  91. "metadata": {
  92. "tags": [
  93. "pdf-ignore"
  94. ]
  95. },
  96. "outputs": [],
  97. "source": [
  98. "# 导入原始CIFAR-10数据\n",
  99. "cifar10_dir = 'daseCV/datasets/cifar-10-batches-py'\n",
  100. "\n",
  101. "# 清空变量,防止多次定义变量(可能造成内存问题)\n",
  102. "try:\n",
  103. " del X_train, y_train\n",
  104. " del X_test, y_test\n",
  105. " print('Clear previously loaded data.')\n",
  106. "except:\n",
  107. " pass\n",
  108. "\n",
  109. "X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)\n",
  110. "\n",
  111. "# 完整性检查,打印出训练和测试数据的大小\n",
  112. "print('Training data shape: ', X_train.shape)\n",
  113. "print('Training labels shape: ', y_train.shape)\n",
  114. "print('Test data shape: ', X_test.shape)\n",
  115. "print('Test labels shape: ', y_test.shape)"
  116. ]
  117. },
  118. {
  119. "cell_type": "code",
  120. "execution_count": null,
  121. "metadata": {
  122. "tags": [
  123. "pdf-ignore"
  124. ]
  125. },
  126. "outputs": [],
  127. "source": [
  128. "# 可视化部分数据\n",
  129. "# 这里我们每个类别展示了7张图片\n",
  130. "classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']\n",
  131. "num_classes = len(classes)\n",
  132. "samples_per_class = 7\n",
  133. "for y, cls in enumerate(classes):\n",
  134. " idxs = np.flatnonzero(y_train == y)\n",
  135. " idxs = np.random.choice(idxs, samples_per_class, replace=False)\n",
  136. " for i, idx in enumerate(idxs):\n",
  137. " plt_idx = i * num_classes + y + 1\n",
  138. " plt.subplot(samples_per_class, num_classes, plt_idx)\n",
  139. " plt.imshow(X_train[idx].astype('uint8'))\n",
  140. " plt.axis('off')\n",
  141. " if i == 0:\n",
  142. " plt.title(cls)\n",
  143. "plt.show()"
  144. ]
  145. },
  146. {
  147. "cell_type": "code",
  148. "execution_count": null,
  149. "metadata": {
  150. "tags": [
  151. "pdf-ignore"
  152. ]
  153. },
  154. "outputs": [],
  155. "source": [
  156. "# 划分训练集,验证集和测试集,除此之外,\n",
  157. "# 我们从训练集中抽取了一小部分作为代码开发的数据,\n",
  158. "# 使用小批量的开发数据集能够快速开发代码\n",
  159. "num_training = 49000\n",
  160. "num_validation = 1000\n",
  161. "num_test = 1000\n",
  162. "num_dev = 500\n",
  163. "\n",
  164. "# 从原始训练集中抽取出num_validation个样本作为验证集\n",
  165. "mask = range(num_training, num_training + num_validation)\n",
  166. "X_val = X_train[mask]\n",
  167. "y_val = y_train[mask]\n",
  168. "\n",
  169. "# 从原始训练集中抽取出num_training个样本作为训练集\n",
  170. "mask = range(num_training)\n",
  171. "X_train = X_train[mask]\n",
  172. "y_train = y_train[mask]\n",
  173. "\n",
  174. "# 从训练集中抽取num_dev个样本作为开发数据集\n",
  175. "mask = np.random.choice(num_training, num_dev, replace=False)\n",
  176. "X_dev = X_train[mask]\n",
  177. "y_dev = y_train[mask]\n",
  178. "\n",
  179. "# 从原始测试集中抽取num_test个样本作为测试集\n",
  180. "mask = range(num_test)\n",
  181. "X_test = X_test[mask]\n",
  182. "y_test = y_test[mask]\n",
  183. "\n",
  184. "print('Train data shape: ', X_train.shape)\n",
  185. "print('Train labels shape: ', y_train.shape)\n",
  186. "print('Validation data shape: ', X_val.shape)\n",
  187. "print('Validation labels shape: ', y_val.shape)\n",
  188. "print('Test data shape: ', X_test.shape)\n",
  189. "print('Test labels shape: ', y_test.shape)"
  190. ]
  191. },
  192. {
  193. "cell_type": "code",
  194. "execution_count": null,
  195. "metadata": {
  196. "tags": [
  197. "pdf-ignore"
  198. ]
  199. },
  200. "outputs": [],
  201. "source": [
  202. "# 预处理:把图片数据rehspae成行向量\n",
  203. "X_train = np.reshape(X_train, (X_train.shape[0], -1))\n",
  204. "X_val = np.reshape(X_val, (X_val.shape[0], -1))\n",
  205. "X_test = np.reshape(X_test, (X_test.shape[0], -1))\n",
  206. "X_dev = np.reshape(X_dev, (X_dev.shape[0], -1))\n",
  207. "\n",
  208. "# 完整性检查,打印出数据的shape\n",
  209. "print('Training data shape: ', X_train.shape)\n",
  210. "print('Validation data shape: ', X_val.shape)\n",
  211. "print('Test data shape: ', X_test.shape)\n",
  212. "print('dev data shape: ', X_dev.shape)"
  213. ]
  214. },
  215. {
  216. "cell_type": "code",
  217. "execution_count": null,
  218. "metadata": {
  219. "tags": [
  220. "pdf-ignore-input"
  221. ]
  222. },
  223. "outputs": [],
  224. "source": [
  225. "# 预处理:减去image的平均值(均值规整化)\n",
  226. "# 第一步:计算训练集中的图像均值\n",
  227. "mean_image = np.mean(X_train, axis=0)\n",
  228. "print(mean_image[:10]) # print a few of the elements\n",
  229. "plt.figure(figsize=(4,4))\n",
  230. "plt.imshow(mean_image.reshape((32,32,3)).astype('uint8')) # visualize the mean image\n",
  231. "plt.show()\n",
  232. "\n",
  233. "# 第二步:所有数据集减去均值\n",
  234. "X_train -= mean_image\n",
  235. "X_val -= mean_image\n",
  236. "X_test -= mean_image\n",
  237. "X_dev -= mean_image\n",
  238. "\n",
  239. "# 第三步:拼接一个bias维,其中所有值都是1(bias trick),\n",
  240. "# SVM可以联合优化数据和bias,即只需要优化一个权值矩阵W\n",
  241. "X_train = np.hstack([X_train, np.ones((X_train.shape[0], 1))])\n",
  242. "X_val = np.hstack([X_val, np.ones((X_val.shape[0], 1))])\n",
  243. "X_test = np.hstack([X_test, np.ones((X_test.shape[0], 1))])\n",
  244. "X_dev = np.hstack([X_dev, np.ones((X_dev.shape[0], 1))])\n",
  245. "\n",
  246. "print(X_train.shape, X_val.shape, X_test.shape, X_dev.shape)"
  247. ]
  248. },
  249. {
  250. "cell_type": "markdown",
  251. "metadata": {},
  252. "source": [
  253. "## SVM分类器\n",
  254. "\n",
  255. "你需要在**daseCV/classifiers/linear_svm.py**里面完成编码\n",
  256. "\n",
  257. "我们已经预先定义了一个函数`compute_loss_naive`,该函数使用循环来计算多分类SVM损失函数"
  258. ]
  259. },
  260. {
  261. "cell_type": "code",
  262. "execution_count": null,
  263. "metadata": {},
  264. "outputs": [],
  265. "source": [
  266. "# 调用朴素版的损失计算函数\n",
  267. "from daseCV.classifiers.linear_svm import svm_loss_naive\n",
  268. "import time\n",
  269. "\n",
  270. "# 生成一个随机的SVM权值矩阵(矩阵值很小)\n",
  271. "W = np.random.randn(3073, 10) * 0.0001 \n",
  272. "\n",
  273. "loss, grad = svm_loss_naive(W, X_dev, y_dev, 0.000005)\n",
  274. "print('loss: %f' % (loss, ))"
  275. ]
  276. },
  277. {
  278. "cell_type": "markdown",
  279. "metadata": {},
  280. "source": [
  281. "从上面的函数返回的`grad`现在是零。请推导支持向量机损失函数的梯度,并在svm_loss_naive中编码实现。\n",
  282. "\n",
  283. "为了检查是否正确地实现了梯度,你可以用数值方法估计损失函数的梯度,并将数值估计与你计算出来的梯度进行比较。我们已经为你提供了检查的代码:"
  284. ]
  285. },
  286. {
  287. "cell_type": "code",
  288. "execution_count": null,
  289. "metadata": {},
  290. "outputs": [],
  291. "source": [
  292. "# 一旦你实现了梯度计算的功能,重新执行下面的代码检查梯度\n",
  293. "\n",
  294. "# 计算损失和W的梯度\n",
  295. "loss, grad = svm_loss_naive(W, X_dev, y_dev, 0.0)\n",
  296. "\n",
  297. "# 数值估计梯度的方法沿着随机几个维度进行计算,并且和解析梯度进行比较,\n",
  298. "# 这两个方法算出来的梯度应该在任何维度上完全一致(相对误差足够小)\n",
  299. "from daseCV.gradient_check import grad_check_sparse\n",
  300. "f = lambda w: svm_loss_naive(w, X_dev, y_dev, 0.0)[0]\n",
  301. "grad_numerical = grad_check_sparse(f, W, grad)\n",
  302. "\n",
  303. "# 把正则化项打开后继续再检查一遍梯度\n",
  304. "# 你没有忘记正则化项吧?(忘了的罚抄100遍(๑•́ ₃•̀๑) )\n",
  305. "loss, grad = svm_loss_naive(W, X_dev, y_dev, 5e1)\n",
  306. "f = lambda w: svm_loss_naive(w, X_dev, y_dev, 5e1)[0]\n",
  307. "grad_numerical = grad_check_sparse(f, W, grad)"
  308. ]
  309. },
  310. {
  311. "cell_type": "markdown",
  312. "metadata": {
  313. "tags": [
  314. "pdf-inline"
  315. ]
  316. },
  317. "source": [
  318. "**问题 1**\n",
  319. "\n",
  320. "有可能会出现某一个维度上的gradcheck没有完全匹配。这个问题是怎么引起的?有必要担心这个问题么?请举一个简单例子,能够导致梯度检查失败。如何改进这个问题?*提示:SVM的损失函数不是严格可微的*\n",
  321. "\n",
  322. "$\\color{blue}{ 你的回答:}$ *在这里填写* \n"
  323. ]
  324. },
  325. {
  326. "cell_type": "code",
  327. "execution_count": null,
  328. "metadata": {},
  329. "outputs": [],
  330. "source": [
  331. "# 接下来实现svm_loss_vectorized函数,目前只计算损失\n",
  332. "# 稍后再计算梯度\n",
  333. "tic = time.time()\n",
  334. "loss_naive, grad_naive = svm_loss_naive(W, X_dev, y_dev, 0.000005)\n",
  335. "toc = time.time()\n",
  336. "print('Naive loss: %e computed in %fs' % (loss_naive, toc - tic))\n",
  337. "\n",
  338. "from daseCV.classifiers.linear_svm import svm_loss_vectorized\n",
  339. "tic = time.time()\n",
  340. "loss_vectorized, _ = svm_loss_vectorized(W, X_dev, y_dev, 0.000005)\n",
  341. "toc = time.time()\n",
  342. "print('Vectorized loss: %e computed in %fs' % (loss_vectorized, toc - tic))\n",
  343. "\n",
  344. "# 两种方法算出来的损失应该是相同的,但是向量化实现的方法应该更快\n",
  345. "print('difference: %f' % (loss_naive - loss_vectorized))"
  346. ]
  347. },
  348. {
  349. "cell_type": "code",
  350. "execution_count": null,
  351. "metadata": {},
  352. "outputs": [],
  353. "source": [
  354. "# 完成svm_loss_vectorized函数,并用向量化方法计算梯度\n",
  355. "\n",
  356. "# 朴素方法和向量化实现的梯度应该相同,但是向量化方法也应该更快\n",
  357. "tic = time.time()\n",
  358. "_, grad_naive = svm_loss_naive(W, X_dev, y_dev, 0.000005)\n",
  359. "toc = time.time()\n",
  360. "print('Naive loss and gradient: computed in %fs' % (toc - tic))\n",
  361. "\n",
  362. "tic = time.time()\n",
  363. "_, grad_vectorized = svm_loss_vectorized(W, X_dev, y_dev, 0.000005)\n",
  364. "toc = time.time()\n",
  365. "print('Vectorized loss and gradient: computed in %fs' % (toc - tic))\n",
  366. "\n",
  367. "# 损失是一个标量,因此很容易比较两种方法算出的值,\n",
  368. "# 而梯度是一个矩阵,所以我们用Frobenius范数来比较梯度的值\n",
  369. "difference = np.linalg.norm(grad_naive - grad_vectorized, ord='fro')\n",
  370. "print('difference: %f' % difference)"
  371. ]
  372. },
  373. {
  374. "cell_type": "markdown",
  375. "metadata": {},
  376. "source": [
  377. "### 随机梯度下降(Stochastic Gradient Descent)\n",
  378. "\n",
  379. "我们现在有了向量化的损失函数表达式和梯度表达式,同时我们计算的梯度和数值梯度是匹配的。\n",
  380. "接下来我们要做SGD。"
  381. ]
  382. },
  383. {
  384. "cell_type": "code",
  385. "execution_count": null,
  386. "metadata": {},
  387. "outputs": [],
  388. "source": [
  389. "# 在linear_classifier.py文件中,编码实现LinearClassifier.train()中的SGD功能,\n",
  390. "# 运行下面的代码\n",
  391. "from daseCV.classifiers import LinearSVM\n",
  392. "svm = LinearSVM()\n",
  393. "tic = time.time()\n",
  394. "loss_hist = svm.train(X_train, y_train, learning_rate=1e-7, reg=2.5e4,\n",
  395. " num_iters=1500, verbose=True)\n",
  396. "toc = time.time()\n",
  397. "print('That took %fs' % (toc - tic))"
  398. ]
  399. },
  400. {
  401. "cell_type": "code",
  402. "execution_count": null,
  403. "metadata": {},
  404. "outputs": [],
  405. "source": [
  406. "# 一个有用的debugging技巧是把损失函数画出来\n",
  407. "plt.plot(loss_hist)\n",
  408. "plt.xlabel('Iteration number')\n",
  409. "plt.ylabel('Loss value')\n",
  410. "plt.show()"
  411. ]
  412. },
  413. {
  414. "cell_type": "code",
  415. "execution_count": null,
  416. "metadata": {},
  417. "outputs": [],
  418. "source": [
  419. "# 完成LinearSVM.predict函数,并且在训练集和验证集上评估其准确性\n",
  420. "y_train_pred = svm.predict(X_train)\n",
  421. "print('training accuracy: %f' % (np.mean(y_train == y_train_pred), ))\n",
  422. "y_val_pred = svm.predict(X_val)\n",
  423. "print('validation accuracy: %f' % (np.mean(y_val == y_val_pred), ))"
  424. ]
  425. },
  426. {
  427. "cell_type": "code",
  428. "execution_count": null,
  429. "metadata": {
  430. "tags": [
  431. "code"
  432. ]
  433. },
  434. "outputs": [],
  435. "source": [
  436. "# 使用验证集来调整超参数(正则化强度和学习率)。\n",
  437. "# 你可以尝试不同的学习速率和正则化项的值;\n",
  438. "# 如果你细心的话,您应该可以在验证集上获得大约0.39的准确率。\n",
  439. "\n",
  440. "# 注意:在搜索超参数时,您可能会看到runtime/overflow的警告。\n",
  441. "# 这是由极端超参值造成的,不是代码的bug。\n",
  442. "\n",
  443. "learning_rates = [1e-7, 5e-5]\n",
  444. "regularization_strengths = [2.5e4, 5e4]\n",
  445. "\n",
  446. "# results是一个字典,把元组(learning_rate, regularization_strength)映射到元组(training_accuracy, validation_accuracy) \n",
  447. "# accuracy是样本中正确分类的比例\n",
  448. "results = {}\n",
  449. "best_val = -1 # 我们迄今为止见过最好的验证集准确率\n",
  450. "best_svm = None # 拥有最高验证集准确率的LinearSVM对象\n",
  451. "\n",
  452. "##############################################################################\n",
  453. "# TODO:\n",
  454. "# 编写代码,通过比较验证集的准确度来选择最佳超参数。\n",
  455. "# 对于每个超参数组合,在训练集上训练一个线性SVM,在训练集和验证集上计算它的精度,\n",
  456. "# 并将精度结果存储在results字典中。此外,在best_val中存储最高验证集准确度,\n",
  457. "# 在best_svm中存储拥有此精度的SVM对象。\n",
  458. "#\n",
  459. "# 提示: \n",
  460. "# 在开发代码时,应该使用一个比较小的num_iter值,这样SVM就不会花费太多时间训练; \n",
  461. "# 一旦您确信您的代码开发完成,您就应该使用一个较大的num_iter值重新训练并验证。\n",
  462. "##############################################################################\n",
  463. "# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****\n",
  464. "\n",
  465. "pass\n",
  466. " \n",
  467. "# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****\n",
  468. " \n",
  469. "# 打印results\n",
  470. "for lr, reg in sorted(results):\n",
  471. " train_accuracy, val_accuracy = results[(lr, reg)]\n",
  472. " print('lr %e reg %e train accuracy: %f val accuracy: %f' % (\n",
  473. " lr, reg, train_accuracy, val_accuracy))\n",
  474. " \n",
  475. "print('best validation accuracy achieved during cross-validation: %f' % best_val)"
  476. ]
  477. },
  478. {
  479. "cell_type": "code",
  480. "execution_count": null,
  481. "metadata": {
  482. "tags": [
  483. "pdf-ignore-input"
  484. ]
  485. },
  486. "outputs": [],
  487. "source": [
  488. "# 可是化交叉验证结果\n",
  489. "import math\n",
  490. "x_scatter = [math.log10(x[0]) for x in results]\n",
  491. "y_scatter = [math.log10(x[1]) for x in results]\n",
  492. "\n",
  493. "# 画出训练集准确率\n",
  494. "marker_size = 100\n",
  495. "colors = [results[x][0] for x in results]\n",
  496. "plt.subplot(2, 1, 1)\n",
  497. "plt.scatter(x_scatter, y_scatter, marker_size, c=colors, cmap=plt.cm.coolwarm)\n",
  498. "plt.colorbar()\n",
  499. "plt.xlabel('log learning rate')\n",
  500. "plt.ylabel('log regularization strength')\n",
  501. "plt.title('CIFAR-10 training accuracy')\n",
  502. "\n",
  503. "# 画出验证集准确率\n",
  504. "colors = [results[x][1] for x in results] # default size of markers is 20\n",
  505. "plt.subplot(2, 1, 2)\n",
  506. "plt.scatter(x_scatter, y_scatter, marker_size, c=colors, cmap=plt.cm.coolwarm)\n",
  507. "plt.colorbar()\n",
  508. "plt.xlabel('log learning rate')\n",
  509. "plt.ylabel('log regularization strength')\n",
  510. "plt.title('CIFAR-10 validation accuracy')\n",
  511. "plt.show()"
  512. ]
  513. },
  514. {
  515. "cell_type": "code",
  516. "execution_count": null,
  517. "metadata": {},
  518. "outputs": [],
  519. "source": [
  520. "# 在测试集上测试最好的SVM分类器\n",
  521. "y_test_pred = best_svm.predict(X_test)\n",
  522. "test_accuracy = np.mean(y_test == y_test_pred)\n",
  523. "print('linear SVM on raw pixels final test set accuracy: %f' % test_accuracy)"
  524. ]
  525. },
  526. {
  527. "cell_type": "code",
  528. "execution_count": null,
  529. "metadata": {
  530. "tags": [
  531. "pdf-ignore-input"
  532. ]
  533. },
  534. "outputs": [],
  535. "source": [
  536. "# 画出每一类的权重\n",
  537. "# 基于您选择的学习速度和正则化强度,画出来的可能不好看\n",
  538. "w = best_svm.W[:-1,:] # 去掉bias\n",
  539. "w = w.reshape(32, 32, 3, 10)\n",
  540. "w_min, w_max = np.min(w), np.max(w)\n",
  541. "classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']\n",
  542. "for i in range(10):\n",
  543. " plt.subplot(2, 5, i + 1)\n",
  544. " \n",
  545. " # 将权重调整为0到255之间\n",
  546. " wimg = 255.0 * (w[:, :, :, i].squeeze() - w_min) / (w_max - w_min)\n",
  547. " plt.imshow(wimg.astype('uint8'))\n",
  548. " plt.axis('off')\n",
  549. " plt.title(classes[i])"
  550. ]
  551. },
  552. {
  553. "cell_type": "markdown",
  554. "metadata": {
  555. "tags": [
  556. "pdf-inline"
  557. ]
  558. },
  559. "source": [
  560. "**问题2**\n",
  561. "\n",
  562. "描述你的可视化权值是什么样子的,并提供一个简短的解释为什么它们看起来是这样的。\n",
  563. "\n",
  564. "$\\color{blue}{ 你的回答: }$ *请在这里填写* \n"
  565. ]
  566. },
  567. {
  568. "cell_type": "markdown",
  569. "metadata": {},
  570. "source": [
  571. "---\n",
  572. "# 重要\n",
  573. "\n",
  574. "这里是作业的结尾处,请执行以下步骤:\n",
  575. "\n",
  576. "1. 点击`File -> Save`或者用`control+s`组合键,确保你最新的的notebook的作业已经保存到谷歌云。\n",
  577. "2. 执行以下代码确保 `.py` 文件保存回你的谷歌云。"
  578. ]
  579. },
  580. {
  581. "cell_type": "code",
  582. "execution_count": null,
  583. "metadata": {},
  584. "outputs": [],
  585. "source": [
  586. "import os\n",
  587. "\n",
  588. "FOLDER_TO_SAVE = os.path.join('drive/My Drive/', FOLDERNAME)\n",
  589. "FILES_TO_SAVE = ['daseCV/classifiers/linear_svm.py', 'daseCV/classifiers/linear_classifier.py']\n",
  590. "\n",
  591. "for files in FILES_TO_SAVE:\n",
  592. " with open(os.path.join(FOLDER_TO_SAVE, '/'.join(files.split('/')[1:])), 'w') as f:\n",
  593. " f.write(''.join(open(files).readlines()))"
  594. ]
  595. }
  596. ],
  597. "metadata": {
  598. "kernelspec": {
  599. "display_name": "Python 3",
  600. "language": "python",
  601. "name": "python3"
  602. },
  603. "language_info": {
  604. "codemirror_mode": {
  605. "name": "ipython",
  606. "version": 3
  607. },
  608. "file_extension": ".py",
  609. "mimetype": "text/x-python",
  610. "name": "python",
  611. "nbconvert_exporter": "python",
  612. "pygments_lexer": "ipython3",
  613. "version": "3.7.0"
  614. }
  615. },
  616. "nbformat": 4,
  617. "nbformat_minor": 1
  618. }