diff --git a/dog-project/README.md b/dog-project/README.md index b91f890..6aa2c71 100644 --- a/dog-project/README.md +++ b/dog-project/README.md @@ -25,16 +25,16 @@ git clone https://github.com/udacity/cn-deep-learning.git cd cn-deep-learning/dog-project ``` -2. 下载[狗狗数据集](https://s3.cn-north-1.amazonaws.com.cn/static-documents/nd101/v4-dataset/dogImages.zip) ,并将数据集解压大存储库中,地点为`项目路径/dogImages`. +2. 下载[狗狗数据集](https://s3.cn-north-1.amazonaws.com.cn/static-documents/nd101/v4-dataset/dogImages.zip) ,并将数据集解压到存储库中,地点为`项目路径/dogImages`. -3. 下载[人类数据集](https://s3.cn-north-1.amazonaws.com.cn/static-documents/nd101/v4-dataset/lfw.zip)。并将数据集解压大存储库中,位置为`项目路径/lfw `。 +3. 下载[人类数据集](https://s3.cn-north-1.amazonaws.com.cn/static-documents/nd101/v4-dataset/lfw.zip)。并将数据集解压到存储库中,位置为`项目路径/lfw `。 4. 为狗狗数据集下载 [VGG-16关键特征](https://s3.cn-north-1.amazonaws.com.cn/static-documents/nd101/v4-dataset/DogVGG16Data.npz) 并将其放置于存储库中,位置为`项目路径/bottleneck_features `。 5. 安装必要的 Python 依赖包 - 对于 __Mac/OSX__: + 对于 __Linux/Mac__: ```bash conda env create -f requirements/dog-mac.yml @@ -56,20 +56,20 @@ cd cn-deep-learning/dog-project jupyter notebook dog_app.ipynb ``` -__注意:__ 我们虽然已经实现了一些代码,让你更快地开始工作,你仍需要实现额外的功能,以回答 notebook 中所有的问题。 -__除非有要求,否则不要修改任何已经包含的代码。__ +__注意:__ 为了能让你更快的开始工作,我们已经提供了一些代码,但是你仍需要实现额外的功能,以回答 notebook 中所有的问题。 +__除非要求,否则不要修改任何已经给出的代码。__ ## 项目评审 -你的项目将会由优达学城的审阅者依据次项目的[评审标准](https://review.udacity.com/#!/rubrics/1080/view)进行审阅。请仔细阅读,并在提交之前自我评估你的项目。你必须通过了规则中的所有要求,才会审核通过。 +你的项目将会由优达学城的审阅者依据次项目的[评审标准](https://review.udacity.com/#!/rubrics/1080/view)进行审阅。请仔细阅读,并在提交之前自我评估你的项目。你必须完成评审标准中的所有要求,最终才会被审核通过。 ## 项目提交 当你准备好提交你的项目时,将下列文件整理并压缩成一个文件,以便上传。 -- 代码完整可运行的文件 `dog_app.ipynb`,所有的代码块都要执行并展示结果,并要求回答所有问题 -- 将你的 notebook 导出为 HTML 或 PDF 格式,并以 `report.html` 或是 `report.pdf` 命名 -- 任何用于项目中,并且并非由我们为这一项目提供的额外数据图片。 +- 代码完整、可运行的文件 `dog_app.ipynb`,所有的代码块都要执行并展示结果,并要求回答所有问题 +- 将你的 notebook 导出为 HTML 或 PDF 格式,并以 `report.html` 或 `report.pdf` 命名 +- 任何用于项目中而非由我们为这一项目提供的额外数据图片。 __请不要将 `dogImages/` 或是 `lfw/` 文件夹中的项目数据包含在内,同样的,请不要将 `bottleneck_features/` 文件夹包含在内。__ -此外,你也可以通过 GitHub 连接提交项目。 +此外,你也可以通过 GitHub 链接提交项目。 diff --git a/dog-project/dog_app.ipynb b/dog-project/dog_app.ipynb index 4c51f1f..2e9ae8f 100644 --- a/dog-project/dog_app.ipynb +++ b/dog-project/dog_app.ipynb @@ -11,9 +11,9 @@ "\n", "除了实现代码外,你还**必须**回答一些与项目和你的实现有关的问题。每一个需要你回答的问题都会以**'问题 X'**为标题。请仔细阅读每个问题,并且在问题后的**'回答'**文字框中写出完整的答案。我们将根据你对问题的回答和撰写代码所实现的功能来对你提交的项目进行评分。\n", "\n", - ">**提示:**Code 和 Markdown 区域可通过 **Shift + Enter** 快捷键运行。此外,Markdown可以通过双击进入编辑模式。\n", + ">**提示:**Code 和 Markdown 单元可通过 **Shift + Enter** 快捷键运行。此外,Markdown单元可以通过双击进入编辑模式。\n", "\n", - "项目中显示为_选做_的部分可以帮助你的项目脱颖而出,而不是仅仅达到通过的最低要求。如果你决定追求更高的挑战,请在此IPython notebook中完成_选做_部分的代码。\n", + "项目中显示为_选做_的部分可以帮助你的项目脱颖而出,而不是仅仅达到通过的最低要求。如果你决定追求更高的挑战,请在此notebook中完成_选做_部分的代码。\n", "\n", "---\n", "### 让我们开始吧\n", @@ -38,7 +38,7 @@ "\n", "---\n", "\n", - "## 步骤 0: 导入数据集\n", + "## Step 0: 导入数据集\n", "\n", "### 导入狗数据集\n", "在下方的代码单元(cell)中,我们导入了一个狗图像的数据集。我们使用scikit-learn库中的`load_files`函数来获取一些变量:\n", @@ -50,9 +50,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from sklearn.datasets import load_files \n", @@ -75,7 +73,7 @@ "# 加载狗品种列表\n", "dog_names = [item[20:-1] for item in sorted(glob(\"dogImages/train/*/\"))]\n", "\n", - "# 打印数据统计描述\n", + "# 打印数据统计结果\n", "print('There are %d total dog categories.' % len(dog_names))\n", "print('There are %s total dog images.\\n' % len(np.hstack([train_files, valid_files, test_files])))\n", "print('There are %d training dog images.' % len(train_files))\n", @@ -89,15 +87,13 @@ "source": [ "### 导入人脸数据集\n", "\n", - "在下方的代码单元中,我们导入人脸图像数据集,文件所在路径存储在`human_files`numpy数组。" + "在下方的代码单元中,我们导入人脸图像数据集,文件所在路径存储在`human_files`numpy数组中。" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "import random\n", @@ -107,7 +103,7 @@ "human_files = np.array(glob(\"lfw/*/*\"))\n", "random.shuffle(human_files)\n", "\n", - "# 打印数据集的统计描述\n", + "# 打印数据集的统计结果\n", "print('There are %d total human images.' % len(human_files))" ] }, @@ -117,9 +113,9 @@ "source": [ "---\n", "\n", - "## 步骤1:检测人类\n", + "## Step 1: 检测人类\n", "\n", - "我们用OpenCV实现的[Haar feature-based cascade classifiers](http://docs.opencv.org/trunk/d7/d8b/tutorial_py_face_detection.html)去检测图像中的人脸。OpenCV提供很多预训练的人脸检测模型,它们以XML文件保存在[github](https://github.com/opencv/opencv/tree/master/data/haarcascades)。我们已经下载了其中一个检测模型,并且把它存储在`haarcascades`的目录中。\n", + "我们用OpenCV实现的[Haar feature-based cascade classifiers](http://docs.opencv.org/trunk/d7/d8b/tutorial_py_face_detection.html)去检测图像中的人脸。OpenCV提供很多预训练的人脸检测模型,它们以XML文件保存在[GitHub](https://github.com/opencv/opencv/tree/master/data/haarcascades)上。我们已经下载了其中一个检测模型,并且把它存储在`haarcascades`的目录中。\n", "\n", "在下一个代码单元中,我们将演示如何使用这个检测模型在样本图像中找到人脸。" ] @@ -127,9 +123,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "import cv2 \n", @@ -141,16 +135,17 @@ "\n", "# 加载彩色(通道顺序为BGR)图像\n", "img = cv2.imread(human_files[3])\n", + "\n", "# 将BGR图像进行灰度化处理\n", "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", "\n", - "# 在图像中找出脸\n", + "# 在图像中找出人脸\n", "faces = face_cascade.detectMultiScale(gray)\n", "\n", - "# 打印图像中检测到的脸的个数\n", + "# 打印图像中检测到的人脸的个数\n", "print('Number of faces detected:', len(faces))\n", "\n", - "# 获取每一个所检测到的脸的识别框\n", + "# 获取每一个所检测到的人脸的识别框\n", "for (x,y,w,h) in faces:\n", " # 将识别框添加到彩色图像中\n", " cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)\n", @@ -169,18 +164,16 @@ "source": [ "在使用任何一个检测模型之前,将图像转换为灰度级是常用过程。`detectMultiScale`函数运行保存在`face_cascade`的分类器,并将灰度图像作为一个参数。\n", "\n", - "在上方的代码中,`faces`是被检测到的脸的numpy数组,其中每一行表示一个被检测到的脸。每一个被检测到的脸都是一个含有4个条目的1维数组,它们表示着被检测到的面部的识别框。数组中的前两个条目(从上方代码中提取出的`x`和`y`)表示着识别框左上角的水平和垂直位置。数组中后面的2个条目(提取为`w`和`h`)表示识别框的宽和高。\n", + "在上方的代码中,`faces`是被检测到的人脸的numpy数组,其中每一行表示一个被检测到的人脸。每一个被检测到的人脸都是一个含有4个条目的1维数组,它们表示着被检测到的面部的识别框。数组中的前两个条目(从上方代码中提取出的`x`和`y`)表示着识别框左上角的水平和垂直位置。数组中后面的2个条目(提取为`w`和`h`)表示识别框的宽和高。\n", "\n", "### 写一个人脸识别器\n", - "我们可以用这个程序去写一个函数,在函数中,当能够在图中识别到人脸的时候返回`True`,否则返回`False`。这个函数被巧妙地命名为`face_detector`,将图像所对应的字符串路径作为输入,并显示在下方代码块中。" + "我们可以用这个程序去写一个函数,在函数中,当能够在图中识别到人脸的时候返回`True`,否则返回`False`。这个函数被命名为`face_detector`,将图像所对应的字符串路径作为输入,并显示在下方代码块中。" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# 如果img_path路径表示的图像检测到了脸,返回\"True\" \n", @@ -201,7 +194,7 @@ "- `human_files`的前100张图像中,能够检测到**人脸**的图像占比多少?\n", "- `dog_files`的前100张图像中,能够检测到**人脸**的图像占比多少?\n", "\n", - "理想情况下,人图像中检测到人脸的概率应当为100%,而狗图像中检测到人脸的概率应该为0%。你会发现我们的算法并不如愿,但结果仍然是可以接受的。我们从每个数据集中提取前100个图像的文件路径,并将它们存储在`human_files_short`和`dog_files_short`中。\n", + "理想情况下,人图像中检测到人脸的比率应当为100%,而狗图像中检测到人脸的比率应该为0%。你会发现我们的算法并不如愿,但结果仍然是可以接受的。我们从每个数据集中提取前100个图像的文件路径,并将它们存储在`human_files_short`和`dog_files_short`中。\n", "\n", "\n", "__回答:__ " @@ -210,17 +203,14 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "human_files_short = human_files[:100]\n", "dog_files_short = train_files[:100]\n", - "# 请不要修改上方代码\n", + "# 请不要修改上方的代码\n", "\n", - "## TODO: 测试face_detector的表现\n", - "## 通过human_files_short和dog_files_short中的图像" + "## TODO: 通过human_files_short和dog_files_short中的图像测试face_detector的表现" ] }, { @@ -237,9 +227,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "## (选做) TODO: 报告另一个面部检测算法在LFW数据集上的表现\n", @@ -252,17 +240,15 @@ "source": [ "---\n", "\n", - "## 步骤 2: 检测狗\n", + "## Step 2: 检测狗\n", "\n", - "在这个部分中,我们使用预训练的[ResNet-50](http://ethereon.github.io/netscope/#/gist/db945b393d40bfa26006)模型去检测图像中的狗。下方的第一行代码就是下载ResNet-50模型,包括已训练的[ImageNet](http://www.image-net.org/)权重。ImageNet这是一个很大很流行的数据集,常被用来做图像分类或者其他的计算机视觉任务。它包含一千万以上的URLs,每一个都链接到[1000 categories](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a)中所对应的一个物体的图像。输入一个图像,这个预训练的ResNet-50模型会返回一个对图像中物体的预测结果(来自ImageNet中可用的类别)。" + "在这个部分中,我们使用经过预训练的[ResNet-50](http://ethereon.github.io/netscope/#/gist/db945b393d40bfa26006)模型去检测图像中是否存在狗。下方的第一行代码就是下载ResNet-50模型,模型包括了已在[ImageNet](http://www.image-net.org/)数据集上训练后的权重。ImageNet是一个很大很流行的数据集,常被用来做图像分类或者其他的计算机视觉任务。它包含一千万以上的URLs,每一个都链接到[1000 categories](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a)中所对应的一个物体的图像。每当输入一个图像,这个经过预训练的ResNet-50模型就会返回一个对图像中物体的预测结果(来自ImageNet中可用的类别)。" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from keras.applications.resnet50 import ResNet50\n", @@ -283,7 +269,7 @@ "(\\text{nb_samples}, \\text{rows}, \\text{columns}, \\text{channels}),\n", "$$\n", "\n", - "其中`nb_samples`表示图像(或者样本)的总数,`rows`, `columns`, 和 `channels`分别表示图像的行数、列数和通道。\n", + "其中`nb_samples`表示图像(或者样本)的总数,`rows`, `columns`, 和 `channels`分别表示图像的行数、列数和通道数。\n", "\n", "下方的`path_to_tensor`函数将彩色图像的字符串型的文件路径作为输入,返回一个4维张量,作为Keras CNN输入。该函数先加载图像,然后将其调整为224×224像素大小。接着,图像就被转化为了将被调整为4维张量的数组。在这个情况下,即使我们正在处理的是彩色的图像,每个图像也是有3个通道。同样的,即使我们正在处理一个单一图像(或者样本),返回的张量的格式一定为\n", "\n", @@ -303,9 +289,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from keras.preprocessing import image \n", @@ -330,19 +314,17 @@ "source": [ "### 使用ResNet-50做预测\n", "\n", - "想要得到 resnet-50 的四维张量,或者 Keras 上其他预训练模型,都需要一些额外的处理。Inception V3、Xception、InceptionResNetV2 的权值是用 TensorFlow 训练出来的,所以需要进行归一化,即缩放到 (-1, 1),通道顺序是 RGB,其他的模型比如VGG16、VGG19、ResNet50的权值是从 Caffe 转过来的,预处理方法是减 ImageNet 均值,即从每个图像的每个像素中减去平均像素(在 BGR 表示为 `[103.939, 116.779, 123.68]`,并从 ImageNet 中所有图像的像素中计算得到),通道顺序是 BGR。`preprocess_input`函数实现了该功能。如果你对此很感兴趣,可以在 [这里](https://github.com/fchollet/keras/blob/master/keras/applications/imagenet_utils.py) 查看 `preprocess_input`的代码。\n", + "想要得到 ResNet-50 的四维张量,或者 Keras 上其他预训练模型,都需要一些额外的处理。Inception V3、Xception、InceptionResNetV2 的权值是用 TensorFlow 训练出来的,所以需要进行归一化,即缩放到 (-1, 1),通道的顺序是 RGB。其他的模型比如VGG16、VGG19、ResNet50的权值是从 Caffe 转过来的,预处理方法是减去 ImageNet 均值,即从每个图像的每个像素中减去平均像素(在 BGR 表示为 `[103.939, 116.779, 123.68]`,并从 ImageNet 中所有图像的像素中计算得到),通道顺序是 BGR。`preprocess_input`函数实现了该功能。如果你对此很感兴趣,可以在 [这里](https://github.com/fchollet/keras/blob/master/keras/applications/imagenet_utils.py) 查看 `preprocess_input`的代码。\n", "\n", "在实现了图像处理的部分之后,我们就可以使用模型来进行预测。这一步通过 `predict` 方法来实现,它返回一个向量,向量的第i个元素表示该图像属于第i个ImageNet类别的概率。这通过如下的 `ResNet50_predict_labels` 函数实现。\n", "\n", - "通过对预测出的向量()取用 argmax 函数(找到有最大概率值的下标序号),我们可以得到一个整数,即模型预测到的物体的类别。进而根据这个 [清单](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),我们能够知道这具体是哪个品种的狗狗。\n" + "通过对预测出的向量()取用 argmax 函数(找到有最大概率值的下标序号),我们可以得到一个整数,即模型预测到的物体的类别。进而根据这个 [清单](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),我们能够知道这具体是哪个品种的狗。\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from keras.applications.resnet50 import preprocess_input, decode_predictions\n", @@ -367,9 +349,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### 如果img_path中的图像可以检测到狗,就返回True\" \n", @@ -384,9 +364,9 @@ "source": [ "### (IMPLEMENTATION) Assess the Dog Detector\n", "\n", - "__问题 3:__ 使用下方代码单元来测试你所完成的`dog_detector`函数的表现力。\n", - "- `human_files_short`中图像检测到狗的百分比?\n", - "- `dog_files_short`中图像检测到狗的百分比?\n", + "__问题 3:__ 使用下方代码单元来测试你所完成的`dog_detector`函数的性能。\n", + "- `human_files_short`中图像检测到狗的比率?\n", + "- `dog_files_short`中图像检测到狗的比率?\n", "\n", "__回答:__ " ] @@ -394,9 +374,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 测试dog_detector函数在human_files_short和dog_files_short的表现" @@ -408,12 +386,12 @@ "source": [ "---\n", "\n", - "## 步骤 3: 创建一个CNN来分类狗品种(来自Scratch)\n", + "## Step 3: 创建一个CNN来分类狗品种(来自Scratch)\n", "\n", "\n", - "现在我们已经实现了一个函数,能够在图像中识别人类及狗狗。但我们需要更进一步的方法,来对狗的类别进行识别。在这一步中,你需要实现一个卷积神经网络来对狗的品种进行分类。你需要__从头实现__你的卷积神经网络(在这一阶段,你还不能使用迁移学习),并且你需要达到超过1%的测试集准确率。在本项目的步骤五种,你还有机会使用迁移学习来实现一个准确率大大提高的模型。\n", + "现在我们已经实现了一个函数,能够在图像中识别人类及狗狗。但我们需要更进一步的方法,来对狗的类别进行识别。在这一步中,你需要实现一个卷积神经网络(CNN)来对狗的品种进行分类。你需要__从头实现__你的卷积神经网络(在这一阶段,你还不能使用迁移学习),并且你需要达到超过1%的测试集准确率。在本项目的步骤5中,你还有机会使用迁移学习来实现一个准确率大幅提高的模型。\n", "\n", - "在添加卷积层的时候,注意不要加上太多的可训练的层。更多的参数意味着更长的训练时间,也就是说你更可能需要一个 GPU 来加速训练过程。万幸的是,Keras 提供了能够轻松预测每次迭代(epoch)花费时间所需的函数。你可以据此推断你算法所需的训练时间。\n", + "在添加卷积层的时候,注意不要添加太多的可训练的层。更多的参数意味着更长的训练时间,也就是说你可能会需要一个 GPU 来加速训练过程。万幸的是,Keras 提供了能够轻松预测每次迭代(epoch)花费时间所需的函数。你可以据此推断你算法所需的训练时间。\n", "\n", "值得注意的是,对狗的图像进行分类是一项极具挑战性的任务。因为即便是一个正常人,也很难区分布列塔尼犬和威尔士史宾格犬。\n", "\n", @@ -442,15 +420,13 @@ "### 数据预处理\n", "\n", "\n", - "通过对每张图像的像素值除以255,我们对图像实现了归一化处理。" + "对每张图像的像素值除以255,来对图像实现归一化处理。" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from PIL import ImageFile \n", @@ -469,7 +445,7 @@ "### (练习) 模型架构\n", "\n", "\n", - "创建一个卷积神经网络来对狗品种进行分类。在你代码块的最后,通过执行 `model.summary()` 来输出你模型的总结信息。\n", + "创建一个卷积神经网络来对狗的品种进行分类。在你代码块的最后,通过执行 `model.summary()` 来输出你模型的总结信息。\n", " \n", "我们已经帮你导入了一些所需的 Python 库,如有需要你可以自行导入。如果你在过程中遇到了困难,如下是给你的一点小提示——该模型能够在5个 epoch 内取得超过1%的测试准确率,并且能在CPU上很快地训练。\n", "\n", @@ -483,9 +459,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D\n", @@ -509,9 +483,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])" @@ -525,25 +497,23 @@ "\n", "在下方代码单元训练模型。使用模型检查点(model checkpointing)来储存具有最低验证集 loss 的模型。\n", "\n", - "当然,你也可以对训练集进行 [数据增强](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html),不过这不是必须的步骤。\n", + "当然,我们很推荐你对训练集进行 [数据扩充](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html),不过这不是必须的步骤。\n", "\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from keras.callbacks import ModelCheckpoint \n", "\n", - "### TODO: 设置训练模型的epochs的数量\n", + "### TODO: 设置训练模型的迭代次数\n", "\n", "epochs = ...\n", "\n", - "### 不要修改下方代码\n", + "### 请不要修改下方的代码\n", "\n", "checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.from_scratch.hdf5', \n", " verbose=1, save_best_only=True)\n", @@ -563,9 +533,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "model.load_weights('saved_models/weights.best.from_scratch.hdf5')" @@ -583,9 +551,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# 获取测试数据集中每一个图像所预测的狗品种的index\n", @@ -602,19 +568,17 @@ "source": [ "---\n", "\n", - "## 步骤 4: 使用一个CNN来区分狗的品种\n", + "## Step 4: 使用一个CNN来区分狗的品种\n", "\n", "为了在不损失准确率的情况下减少训练时间,我们可以使用迁移学习来训练CNN。在以下步骤中,你可以尝试使用迁移学习来训练你自己的CNN。\n", "\n", - "### 得到从图像中提取的特征向量(Bottleneck Features)" + "### 得到从图像中提取的瓶颈特征(Bottleneck Features)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "bottleneck_features = np.load('bottleneck_features/DogVGG16Data.npz')\n", @@ -635,9 +599,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "VGG16_model = Sequential()\n", @@ -657,9 +619,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "VGG16_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])" @@ -675,9 +635,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.VGG16.hdf5', \n", @@ -698,9 +656,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "VGG16_model.load_weights('saved_models/weights.best.VGG16.hdf5')" @@ -711,15 +667,13 @@ "metadata": {}, "source": [ "### 测试模型\n", - "现在,我们可以测试此CNN在狗图像测试数据集中识别品种的效果如何。我们在下方打印出测试准确率。" + "现在,我们可以测试此CNN在狗图像测试数据集中识别品种的效果如何。在下方打印出测试准确率。" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# 获取测试数据集中每一个图像所预测的狗品种的index\n", @@ -740,15 +694,13 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from extract_bottleneck_features import *\n", "\n", "def VGG16_predict_breed(img_path):\n", - " # 提取bottleneck特征\n", + " # 提取瓶颈特征\n", " bottleneck_feature = extract_VGG16(path_to_tensor(img_path))\n", " # 获取预测向量\n", " predicted_vector = VGG16_model.predict(bottleneck_feature)\n", @@ -762,11 +714,11 @@ "source": [ "---\n", "\n", - "## 步骤 5: 建立一个CNN来分类狗的品种(使用迁移学习)\n", + "## Step 5: 建立一个CNN来分类狗的品种(使用迁移学习)\n", "\n", "现在你将使用迁移学习来建立一个CNN,从而可以从图像中识别狗的品种。你的CNN在测试集上的准确率必须至少达到60%。\n", "\n", - "在步骤4中,我们使用了迁移学习来创建一个使用VGG-16 bottleneck特征的CNN。在本部分内容中,你必须使用另一个预训练模型的bottleneck特征。为了让这个任务更易实现,我们已经预先为目前keras中所有可用的网络计算了特征。\n", + "在步骤4中,我们使用了迁移学习来创建一个使用VGG-16 瓶颈特征的CNN。在本部分内容中,你必须使用另一个预训练模型的瓶颈特征。为了让这个任务更易实现,我们已经预先为目前keras中所有可用的网络计算了瓶颈特征。\n", "- [VGG-19](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogVGG19Data.npz) bottleneck features\n", "- [ResNet-50](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogResnet50Data.npz) bottleneck features\n", "- [Inception](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogInceptionV3Data.npz) bottleneck features\n", @@ -776,12 +728,12 @@ "\n", " Dog{network}Data.npz\n", "\n", - "其中`{network}`指上方文件名`VGG19`、`Resnet50`、`InceptionV3`或`Xception`中的一个。选择上方架构中的一个,下载相对应的bottleneck特征,并将所下载的文件保存在目录`bottleneck_features/`中。\n", + "其中`{network}`指上方文件名`VGG19`、`Resnet50`、`InceptionV3`或`Xception`中的一个。选择上方架构中的一个,下载相对应的瓶颈特征,并将所下载的文件保存在目录`bottleneck_features/`中。\n", "\n", "\n", - "### (练习) 获取Bottleneck特征\n", + "### (练习) 获取瓶颈特征\n", "\n", - "在下方代码块中,通过运行下方代码提取训练、测试与验证集相对应的bottleneck特征。\n", + "在下方代码块中,通过运行下方代码提取训练、测试与验证集相对应的瓶颈特征。\n", "\n", " bottleneck_features = np.load('bottleneck_features/Dog{network}Data.npz')\n", " train_{network} = bottleneck_features['train']\n", @@ -792,12 +744,10 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ - "### TODO: 从另一个预训练的CNN获取bottleneck特征" + "### TODO: 从另一个预训练的CNN获取瓶颈特征" ] }, { @@ -819,9 +769,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 定义你的框架" @@ -837,9 +785,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 编译模型" @@ -853,15 +799,13 @@ "\n", "在下方代码单元中训练你的模型。使用模型检查点(model checkpointing)来储存具有最低验证集 loss 的模型。\n", "\n", - "当然,你也可以对训练集进行 [数据增强](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html),不过这不是必须的步骤。\n" + "当然,我们推荐你对训练集进行 [数据扩充](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html),不过这不是必须的步骤。\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 训练模型" @@ -877,9 +821,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 加载具有最佳验证loss的模型权重" @@ -897,9 +839,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 在测试集上计算分类准确率" @@ -912,24 +852,22 @@ "### (练习) 使用模型测试狗的品种\n", "\n", "\n", - "实现一个函数,它的输入为图像路径,功能为预测对应图像的类别,输出为你模型预测出的狗类别(`Affenpinscher`, `Afghan_hound`等)。\n", + "实现一个函数,它的输入为图像路径,功能为预测对应图像的类别,输出为你模型预测出的狗的类别(`Affenpinscher`, `Afghan_hound`等)。\n", "\n", - "与步骤5中的模拟函数类似,你的函数应当包含如下三个步骤:\n", + "与step4中的函数类似,你的函数应当包含如下三个步骤:\n", "\n", - "1. 根据选定的模型提取图像特征(bottleneck features)\n", - "2. 将图像特征输输入到你的模型中,并返回预测向量。注意,在该向量上使用 argmax 函数可以返回狗种类的序号。\n", + "1. 根据选定的模型提取瓶颈特征(bottleneck features)\n", + "2. 将瓶颈特征输输入到你的模型中,并返回预测向量。注意,在该向量上使用 argmax 函数可以返回狗种类的序号。\n", "3. 使用在步骤0中定义的 `dog_names` 数组来返回对应的狗种类名称。\n", "\n", - "提取图像特征过程中使用到的函数可以在 `extract_bottleneck_features.py` 中找到。同时,他们应已在之前的代码块中被导入。根据你选定的 CNN 网络,你可以使用 `extract_{network}` 函数来获得对应的图像特征,其中 `{network}` 代表 `VGG19`, `Resnet50`, `InceptionV3`, 或 `Xception` 中的一个。\n", + "提取瓶颈特征过程中使用到的函数可以在 `extract_bottleneck_features.py` 中找到。同时,他们应已在之前的代码块中被导入。根据你选定的 CNN 网络,你可以使用 `extract_{network}` 函数来获得对应的图像特征,其中 `{network}` 为 `VGG19`, `Resnet50`, `InceptionV3`, 或 `Xception` 中的一个。\n", " " ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 写一个函数,该函数将图像的路径作为输入\n", @@ -942,18 +880,18 @@ "source": [ "---\n", "\n", - "## 步骤 6: 完成你的算法\n", + "## Step 6: 完成你的算法\n", "\n", "\n", - "实现一个算法,它的输入为图像的路径,它能够区分图像是否包含一个人、狗或都不包含,然后:\n", + "设计并实现一个算法,它的输入为图像的路径,并能够判断图像是否包含人、包含狗或都不包含,然后:\n", "\n", - "- 如果从图像中检测到一只__狗__,返回被预测的品种。\n", - "- 如果从图像中检测到__人__,返回最相像的狗品种。\n", + "- 如果从图像中检测到了__狗__,返回被预测的狗的品种。\n", + "- 如果从图像中检测到了__人__,返回最相像的狗的品种。\n", "- 如果两者都不能在图像中检测到,输出错误提示。\n", "\n", - "我们非常欢迎你来自己编写检测图像中人类与狗的函数,你可以随意地使用上方完成的`face_detector`和`dog_detector`函数。你__需要__在步骤5使用你的CNN来预测狗品种。\n", + "我们非常欢迎你来自己编写检测图像中人类与狗的函数,你可以随意地使用之前完成的`face_detector`和`dog_detector`函数。你__需要__使用步骤5中的CNN来预测狗的品种。\n", "\n", - "下面提供了算法的示例输出,但你可以自由地设计自己的模型!\n", + "下面提供了一个示例算法的输出,但你可以自由地设计用户体验!\n", "\n", "![Sample Human Output](images/sample_human_output.png)\n", "\n", @@ -964,13 +902,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "### TODO: 设计你的算法\n", - "### 自由地使用所需的代码单元数吧" + "### 你可以使用任意数量的代码单元" ] }, { @@ -979,13 +915,13 @@ "source": [ "---\n", "\n", - "## 步骤 7: 测试你的算法\n", + "## Step 7: 测试你的算法\n", "\n", "在这个部分中,你将尝试一下你的新算法!算法认为__你__看起来像什么类型的狗?如果你有一只狗,它可以准确地预测你的狗的品种吗?如果你有一只猫,它会将你的猫误判为一只狗吗?\n", "\n", "### (练习) 在样本图像上测试你的算法!\n", "\n", - "在你的电脑上,用至少6张图片来测试你的算法。请自由地使用任何一张你想用的图片。不过请至少使用两张人类图片和两张狗的图片。\n", + "在你的电脑上,使用至少6张图片来测试你的算法。请自由地使用任何一张你想用的图片,不过至少使用两张人类图片和两张狗的图片。\n", "\n", "__问题 6:__ 输出结果比你预想的要好吗 :) ?或者更糟 :( ?请提出至少三点改进你的模型的方法。\n", "\n", @@ -995,29 +931,27 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ - "## TODO: 在你的电脑上,在步骤6中,至少在6张图片上运行你的算法。\n", - "## 自由地使用所需的代码单元数吧" + "## TODO: 在你的电脑上,至少在6张图片上测试step6中的算法。\n", + "## 你可以使用任意数量的代码单元" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**注意: 当你写完了所有的代码,并且回答了所有的问题。你就可以把你的 iPython Notebook 导出成 HTML 文件。你可以在菜单栏,这样导出File -> Download as -> HTML (.html)把这个 HTML 和这个 iPython notebook 一起做为你的作业提交。**" + "**注意: 当你写完了所有的代码,并且回答了所有的问题。你就可以把你的 notebook 导出成 HTML 文件。你可以在菜单栏,这样导出:File -> Download as -> HTML (.html)。把 HTML 和 notebook 文件一起作为你的作业提交。**" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [conda root]", + "display_name": "Python 3", "language": "python", - "name": "conda-root-py" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1029,7 +963,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.3" + "version": "3.6.4" } }, "nbformat": 4,