{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "id": "x4HI2mpwlrcn" }, "outputs": [], "source": [ "##### Copyright 2019 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "id": "679Lmwt3l1Bk", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "DSPCom-KmApV" }, "source": [ "# 卷积神经网络(Convolutional Neural Network, CNN)" ] }, { "cell_type": "markdown", "metadata": { "id": "klAltGp8ycek" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
在 TensorFlow.org 上查看 在 Google Colab 中运行 在 GitHub 上查看源代码 下载笔记本
" ] }, { "cell_type": "markdown", "metadata": { "id": "qLGkt5qiyz4E" }, "source": [ "本教程展示了如何训练一个简单的[卷积神经网络](https://developers.google.com/machine-learning/glossary/#convolutional_neural_network) (CNN) 来对 [CIFAR 图像](https://www.cs.toronto.edu/~kriz/cifar.html)进行分类。由于本教程使用的是 [Keras Sequential API](https://tensorflow.google.cn/guide/keras/overview),创建和训练模型只需要几行代码。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "m7KBpffWzlxH" }, "source": [ "### 导入 TensorFlow" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "iAve6DCL4JH4", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "import tensorflow as tf\n", "\n", "from tensorflow.keras import datasets, layers, models\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": { "id": "jRFxccghyMVo" }, "source": [ "### 下载并准备 CIFAR10 数据集\n", "\n", "CIFAR10 数据集包含 10 类,共 60000 张彩色图片,每类图片有 6000 张。此数据集中 50000 个样例被作为训练集,剩余 10000 个样例作为测试集。类之间相互独立,不存在重叠的部分。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "JWoEqyMuXFF4", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()\n", "\n", "# Normalize pixel values to be between 0 and 1\n", "train_images, test_images = train_images / 255.0, test_images / 255.0" ] }, { "cell_type": "markdown", "metadata": { "id": "7wArwCTJJlUa" }, "source": [ "### 验证数据\n", "\n", "为了验证数据集看起来是否正确,我们绘制训练集中的前 25 张图像并在每张图像下方显示类名称:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "K3PAELE2eSU9", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n", " 'dog', 'frog', 'horse', 'ship', 'truck']\n", "\n", "plt.figure(figsize=(10,10))\n", "for i in range(25):\n", " plt.subplot(5,5,i+1)\n", " plt.xticks([])\n", " plt.yticks([])\n", " plt.grid(False)\n", " plt.imshow(train_images[i])\n", " # The CIFAR labels happen to be arrays, \n", " # which is why you need the extra index\n", " plt.xlabel(class_names[train_labels[i][0]])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "Oewp-wYg31t9" }, "source": [ "### 构造卷积神经网络模型" ] }, { "cell_type": "markdown", "metadata": { "id": "3hQvqXpNyN3x" }, "source": [ "下方展示的 6 行代码声明了了一个常见卷积神经网络,由几个 [Conv2D](https://tensorflow.google.cn/api_docs/python/tf/keras/layers/Conv2D) 和 [MaxPooling2D](https://tensorflow.google.cn/api_docs/python/tf/keras/layers/MaxPool2D) 层组成。\n", "\n", "CNN 将形状为 (image_height, image_width, color_channels) 的张量作为输入,忽略批次大小。如果您不熟悉这些维度,color_channels 是指 (R,G,B)。在此示例中,您将配置 CNN 以处理形状为 (32, 32, 3) 的输入,即 CIFAR 图像的格式。您可以通过将参数 `input_shape` 传递给第一层来实现此目的。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "L9YmGQBQPrdn", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "model = models.Sequential()\n", "model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))\n", "model.add(layers.MaxPooling2D((2, 2)))\n", "model.add(layers.Conv2D(64, (3, 3), activation='relu'))\n", "model.add(layers.MaxPooling2D((2, 2)))\n", "model.add(layers.Conv2D(64, (3, 3), activation='relu'))" ] }, { "cell_type": "markdown", "metadata": { "id": "lvDVFkg-2DPm" }, "source": [ "到目前为止,模型的架构如下:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "8-C4XBg4UTJy", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "_j-AXYeZ2GO5" }, "source": [ "在上面的结构中,您可以看到每个 Conv2D 和 MaxPooling2D 层的输出都是一个三维的张量 (Tensor),其形状描述了 (height, width, channels)。越深的层中,宽度和高度都会收缩。每个 Conv2D 层输出的通道数量 (channels) 取决于声明层时的第一个参数(如:上面代码中的 32 或 64)。这样,由于宽度和高度的收缩,您便可以(从运算的角度)增加每个 Conv2D 层输出的通道数量 (channels)。" ] }, { "cell_type": "markdown", "metadata": { "id": "_v8sVOtG37bT" }, "source": [ "### 增加 Dense 层\n", "\n", "为了完成模型,您需要将卷积基(形状为 (4, 4, 64))的最后一个输出张量馈送到一个或多个 Dense 层以执行分类。Dense 层将向量作为输入(即 1 维),而当前输出为 3 维张量。首先,将 3 维输出展平(或展开)为 1 维,然后在顶部添加一个或多个 Dense 层。CIFAR 有 10 个输出类,因此使用具有 10 个输出的最终 Dense 层。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mRs95d6LUVEi", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "model.add(layers.Flatten())\n", "model.add(layers.Dense(64, activation='relu'))\n", "model.add(layers.Dense(10))" ] }, { "cell_type": "markdown", "metadata": { "id": "ipGiQMcR4Gtq" }, "source": [ "下面是模型的完整架构:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "8Yu_m-TZUWGX", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "xNKXi-Gy3RO-" }, "source": [ "网络摘要显示 (4, 4, 64) 输出在经过两个 Dense 层之前被展平为形状为 (1024) 的向量。" ] }, { "cell_type": "markdown", "metadata": { "id": "P3odqfHP4M67" }, "source": [ "### 编译并训练模型" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MdDzI75PUXrG", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "model.compile(optimizer='adam',\n", " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", " metrics=['accuracy'])\n", "\n", "history = model.fit(train_images, train_labels, epochs=10, \n", " validation_data=(test_images, test_labels))" ] }, { "cell_type": "markdown", "metadata": { "id": "jKgyC5K_4O0d" }, "source": [ "### 评估模型" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "gtyDF0MKUcM7", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "plt.plot(history.history['accuracy'], label='accuracy')\n", "plt.plot(history.history['val_accuracy'], label = 'val_accuracy')\n", "plt.xlabel('Epoch')\n", "plt.ylabel('Accuracy')\n", "plt.ylim([0.5, 1])\n", "plt.legend(loc='lower right')\n", "\n", "test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "0LvwaKhtUdOo", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "print(test_acc)" ] }, { "cell_type": "markdown", "metadata": { "id": "8cfJ8AR03gT5" }, "source": [ "您的简单 CNN 的测试准确率已达到 70% 以上。对于只有几行的代码来说,效果不错!对于另一种 CNN 风格,请参阅[适合专家的 TensorFlow 2 快速入门](https://tensorflow.google.cn/tutorials/quickstart/advanced)示例,此示例使用了 Keras 子类化 API 和 `tf.GradientTape`。" ] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "cnn.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 0 }