{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Introduction\n**Who this notebook is for**  \n这本笔记本是为任何有兴趣使用张量处理单元(tpu)创建基线模型并开始提交木薯叶疾病分类竞赛的人准备的。如果你参加过Kaggle深度学习入门和//或Kaggle计算机视觉课程，你会发现这本笔记本是一个很好的起点，可以将你在我们的微课程中所学到的知识应用到比赛中。\n\n**How to use this notebook**  \n请随意使用本笔记本作为如何使用TensorFlow和张量处理单元(tpu)构建初步图像分类模型的指南。您可以通过点击右上角的相应按钮来复制和编辑笔记本，这将在您的Kaggle帐户中创建您自己的笔记本副本。从那里，你所做的任何编辑都将是独一无二的，你自己的笔记本拷贝!\n\n**TPUs with TensorFlow**  \n我们将使用TensorFlow和Keras来构建我们的计算机视觉模型，并使用tpu来训练我们的模型并进行预测。如果您想了解更多关于tpu的知识，请务必查看我们的“与我一起学习:张量处理单元(tpu)入门”视频。 **[Learn With Me: Getting Started with Tensor Processing Units (TPUs)](https://youtu.be/1pdwRQ1DQfY)** video.  \n\n**References**  \n这款笔记本是使用以下由Kagglers创建的惊人资源构建的:\n- **Martin Gorner:** [Getting Started With 100 Flowers on TPU](https://www.kaggle.com/mgornergoogle/getting-started-with-100-flowers-on-tpu)\n- **Amy Jang:** [TensorFlow + Transfer Learning: Melanoma](https://www.kaggle.com/amyjang/tensorflow-transfer-learning-melanoma)\n- **Phil Culliton:** [A Simple TF 2.1 Notebook](https://www.kaggle.com/philculliton/a-simple-tf-2-1-notebook)","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":0.039382,"end_time":"2020-11-19T21:45:23.042097","exception":false,"start_time":"2020-11-19T21:45:23.002715","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# Tensor Processing Units (TPUs)\n\n张量处理单元(Tensor Processing Units, tpu)是专门用于深度学习任务的硬件加速器。所有Kagglers每周都有30个小时的空闲TPU时间，单次会议最多可以使用3个小时(尽管如果你想增加你的TPU配额，可以考虑提交一个典型的TPU笔记本给我们的TPU Star计划!)\n你可以在这里阅读Kaggle关于TPU的文档，并在这里查看TPU Star笔记本。","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","papermill":{"duration":0.035886,"end_time":"2020-11-19T21:45:23.118837","exception":false,"start_time":"2020-11-19T21:45:23.082951","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# 设置环境","metadata":{"papermill":{"duration":0.037375,"end_time":"2020-11-19T21:45:23.192515","exception":false,"start_time":"2020-11-19T21:45:23.15514","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import math, re, os\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\nfrom tensorflow import keras\nfrom functools import partial\nfrom sklearn.model_selection import train_test_split\nprint(\"Tensorflow version \" + tf.__version__)","metadata":{"papermill":{"duration":6.890298,"end_time":"2020-11-19T21:45:30.119979","exception":false,"start_time":"2020-11-19T21:45:23.229681","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:40.313464Z","iopub.execute_input":"2023-04-17T03:46:40.313945Z","iopub.status.idle":"2023-04-17T03:46:49.567369Z","shell.execute_reply.started":"2023-04-17T03:46:40.313905Z","shell.execute_reply":"2023-04-17T03:46:49.565885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 检测TPU\n我们在这里用代码所做的是确保我们将通过TPU发送数据。你要找的是“副本数量:8”的打印输出，对应于TPU的8个核心。如果你的打印结果显示“副本数量:1”，那么你的笔记本上可能没有启用tpu。  \n\n要启用tpu，请导航到右侧面板，并单击“加速器”。在下拉菜单中选择“TPU”。\n\n果您想了解更多TPU故障排除和优化指南，请查看我们的 **[Learn With Me: Troubleshooting and Optimizing TPUs video](https://youtu.be/BSeWHzjMHMU)**.  ","metadata":{"papermill":{"duration":0.037444,"end_time":"2020-11-19T21:45:30.195328","exception":false,"start_time":"2020-11-19T21:45:30.157884","status":"completed"},"tags":[]}},{"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)","metadata":{"papermill":{"duration":4.150374,"end_time":"2020-11-19T21:45:34.382816","exception":false,"start_time":"2020-11-19T21:45:30.232442","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:49.570091Z","iopub.execute_input":"2023-04-17T03:46:49.571184Z","iopub.status.idle":"2023-04-17T03:46:54.834946Z","shell.execute_reply.started":"2023-04-17T03:46:49.571122Z","shell.execute_reply":"2023-04-17T03:46:54.833553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 设置变量\n我们将在笔记本上设置一些变量。\n\n如果您碰巧使用了私有数据集，您还需要确保您的笔记本上附加了谷歌云软件开发工具包(SDK)。你可以在笔记本电脑顶部的Add-ons下拉菜单中找到谷歌Cloud SDK。谷歌云软件开发工具包(SDK)的文档可以在这里找到。","metadata":{"papermill":{"duration":0.038122,"end_time":"2020-11-19T21:45:34.458722","exception":false,"start_time":"2020-11-19T21:45:34.4206","status":"completed"},"tags":[]}},{"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nGCS_PATH = KaggleDatasets().get_gcs_path()\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\nIMAGE_SIZE = [512, 512]\nCLASSES = ['0', '1', '2', '3', '4']\nEPOCHS = 25","metadata":{"papermill":{"duration":145.219568,"end_time":"2020-11-19T21:47:59.715925","exception":false,"start_time":"2020-11-19T21:45:34.496357","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:54.836774Z","iopub.execute_input":"2023-04-17T03:46:54.837474Z","iopub.status.idle":"2023-04-17T03:46:55.205527Z","shell.execute_reply.started":"2023-04-17T03:46:54.837421Z","shell.execute_reply":"2023-04-17T03:46:55.204479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load the data\n如果你在Learn中主要使用笔记本，你可能已经注意到数据导入和格式化是为你准备的。但因为我们处理的是竞争数据，所以我们必须自己处理这部分的渠道。\n\n我们正在处理的数据已经被格式化为“TFRecords”，这是一种用于存储二进制记录序列的格式。' TFRecords '在TPU上工作得非常好，它允许我们通过TPU发送少量的大文件进行处理。\n\n如果你想了解更多关于TFRecords的信息，甚至想尝试自己创建他们， check out this **[TFRecords Basics notebook](https://www.kaggle.com/ryanholbrook/tfrecords-basics)** and **[corresponding video](https://youtu.be/KgjaC9VeOi8)** from Kaggle Data Scientist Ryan Holbrook.  \n\n因为我们的数据只包含“训练”和“测试”图像，所以我们将使用“train_test_split()”函数将“训练”数据拆分为“训练”和“验证”数据。","metadata":{"papermill":{"duration":0.037843,"end_time":"2020-11-19T21:47:59.792061","exception":false,"start_time":"2020-11-19T21:47:59.754218","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## 解码数据\n在下面的代码块中，我们将设置一系列函数，允许我们将图像转换为张量，以便我们可以在我们的模型中使用它们。我们还将对数据进行规范化。我们的图像使用的是范围为[0,255]的“红、蓝、绿(RBG)”刻度，通过规范化，我们将每个像素的值设置为范围为[0,1]的数字。","metadata":{"papermill":{"duration":0.038439,"end_time":"2020-11-19T21:47:59.869037","exception":false,"start_time":"2020-11-19T21:47:59.830598","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image","metadata":{"papermill":{"duration":0.04859,"end_time":"2020-11-19T21:47:59.955731","exception":false,"start_time":"2020-11-19T21:47:59.907141","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.208730Z","iopub.execute_input":"2023-04-17T03:46:55.209323Z","iopub.status.idle":"2023-04-17T03:46:55.216141Z","shell.execute_reply.started":"2023-04-17T03:46:55.209253Z","shell.execute_reply":"2023-04-17T03:46:55.214483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"如果你回想一下机器学习导论，你可能会记得我们如何设置变量X和y，代表我们的特征X和预测目标y。这段代码完成了类似的事情，尽管我们的特征用术语图像表示，预测目标用术语目标表示，而不是使用标签X和y。\n\n您可能还注意到，该函数用于处理未标记的图像。这是因为我们的测试图像没有任何标签。  ","metadata":{"papermill":{"duration":0.039515,"end_time":"2020-11-19T21:48:00.034969","exception":false,"start_time":"2020-11-19T21:47:59.995454","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def read_tfrecord(example, labeled):\n    tfrecord_format = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.int64)\n    } if labeled else {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"image_name\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    if labeled:\n        label = tf.cast(example['target'], tf.int32)\n        return image, label\n    idnum = example['image_name']\n    return image, idnum","metadata":{"papermill":{"duration":0.052475,"end_time":"2020-11-19T21:48:00.127039","exception":false,"start_time":"2020-11-19T21:48:00.074564","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.218323Z","iopub.execute_input":"2023-04-17T03:46:55.219427Z","iopub.status.idle":"2023-04-17T03:46:55.229089Z","shell.execute_reply.started":"2023-04-17T03:46:55.219373Z","shell.execute_reply":"2023-04-17T03:46:55.227534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"我们将使用下面的函数来加载数据集。TPU的优点之一是我们可以一次在TPU上运行多个文件，这说明了使用TPU的速度优势。为了充分利用这一点，我们希望确保在数据流进入时立即使用数据，而不是创建数据流瓶颈。","metadata":{"papermill":{"duration":0.038946,"end_time":"2020-11-19T21:48:00.205445","exception":false,"start_time":"2020-11-19T21:48:00.166499","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(partial(read_tfrecord, labeled=labeled), num_parallel_calls=AUTOTUNE)\n    return dataset","metadata":{"papermill":{"duration":0.073623,"end_time":"2020-11-19T21:48:00.328703","exception":false,"start_time":"2020-11-19T21:48:00.25508","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.232159Z","iopub.execute_input":"2023-04-17T03:46:55.232611Z","iopub.status.idle":"2023-04-17T03:46:55.240716Z","shell.execute_reply.started":"2023-04-17T03:46:55.232561Z","shell.execute_reply":"2023-04-17T03:46:55.239346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## A note on using train_test_split()\n虽然我使用了train_test_split()来创建训练数据集和验证数据集，但是可以考虑使用交叉验证。","metadata":{"papermill":{"duration":0.03958,"end_time":"2020-11-19T21:48:00.416432","exception":false,"start_time":"2020-11-19T21:48:00.376852","status":"completed"},"tags":[]}},{"cell_type":"code","source":"TRAINING_FILENAMES, VALID_FILENAMES = train_test_split(\n    tf.io.gfile.glob(GCS_PATH + '/train_tfrecords/ld_train*.tfrec'),\n    test_size=0.35, random_state=5\n)\n\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/test_tfrecords/ld_test*.tfrec')","metadata":{"papermill":{"duration":0.225941,"end_time":"2020-11-19T21:48:00.687385","exception":false,"start_time":"2020-11-19T21:48:00.461444","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.242366Z","iopub.execute_input":"2023-04-17T03:46:55.243430Z","iopub.status.idle":"2023-04-17T03:46:55.351213Z","shell.execute_reply.started":"2023-04-17T03:46:55.243374Z","shell.execute_reply":"2023-04-17T03:46:55.350092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Adding in augmentations \n您已经在Kaggle Learn的计算机视觉:数据增强课程中了解了增强，在这里我应用了通过TensorFlow提供的增强。你可以在TensorFlow tf中阅读更多关于这些增强(以及所有其他可用的增强!)图像文档。 \n\n如果你有兴趣学习如何创建和使用自定义增强，请查看Kaggle Grandmaster Chris Deotte提供的这些旋转增强GPU/TPU和GPU/TPU上的CutMix和MixUp。, check out these **[Rotation Augmentation GPU/TPU](https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96)** and **[CutMix and MixUp on GPU/TPU](https://www.kaggle.com/cdeotte/cutmix-and-mixup-on-gpu-tpu)** from Kaggle Grandmaster Chris Deotte.","metadata":{"papermill":{"duration":0.038372,"end_time":"2020-11-19T21:48:00.765394","exception":false,"start_time":"2020-11-19T21:48:00.727022","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def data_augment(image, label):\n    # 多亏了下面函数中的dataset.prefetch(AUTO)语句，这在TPU上基本上是免费的。 \n    # 数据管道代码在TPU的“CPU”部分执行，而TPU本身则在计算梯度。\n    image = tf.image.random_flip_left_right(image)\n    return image, label","metadata":{"papermill":{"duration":0.047715,"end_time":"2020-11-19T21:48:00.851918","exception":false,"start_time":"2020-11-19T21:48:00.804203","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.352845Z","iopub.execute_input":"2023-04-17T03:46:55.353176Z","iopub.status.idle":"2023-04-17T03:46:55.359126Z","shell.execute_reply.started":"2023-04-17T03:46:55.353145Z","shell.execute_reply":"2023-04-17T03:46:55.357896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 定义数据加载方法\n下面的函数将用于加载我们的“训练”、“验证”和“测试”数据集，以及打印出每个数据集中的图像数量。","metadata":{"papermill":{"duration":0.038742,"end_time":"2020-11-19T21:48:00.930185","exception":false,"start_time":"2020-11-19T21:48:00.891443","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)  \n    dataset = dataset.map(data_augment, num_parallel_calls=AUTOTUNE)  \n    dataset = dataset.repeat()\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","metadata":{"papermill":{"duration":0.052326,"end_time":"2020-11-19T21:48:01.021791","exception":false,"start_time":"2020-11-19T21:48:00.969465","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.360597Z","iopub.execute_input":"2023-04-17T03:46:55.360924Z","iopub.status.idle":"2023-04-17T03:46:55.370669Z","shell.execute_reply.started":"2023-04-17T03:46:55.360892Z","shell.execute_reply":"2023-04-17T03:46:55.369449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALID_FILENAMES, labeled=True, ordered=ordered) \n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","metadata":{"papermill":{"duration":0.049787,"end_time":"2020-11-19T21:48:01.112145","exception":false,"start_time":"2020-11-19T21:48:01.062358","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.375072Z","iopub.execute_input":"2023-04-17T03:46:55.375467Z","iopub.status.idle":"2023-04-17T03:46:55.381780Z","shell.execute_reply.started":"2023-04-17T03:46:55.375428Z","shell.execute_reply":"2023-04-17T03:46:55.380332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_test_dataset(ordered=False):\n    dataset = load_dataset(TEST_FILENAMES, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","metadata":{"papermill":{"duration":0.050395,"end_time":"2020-11-19T21:48:01.207665","exception":false,"start_time":"2020-11-19T21:48:01.15727","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.382798Z","iopub.execute_input":"2023-04-17T03:46:55.383120Z","iopub.status.idle":"2023-04-17T03:46:55.392298Z","shell.execute_reply.started":"2023-04-17T03:46:55.383089Z","shell.execute_reply":"2023-04-17T03:46:55.390898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)","metadata":{"papermill":{"duration":0.05422,"end_time":"2020-11-19T21:48:01.304611","exception":false,"start_time":"2020-11-19T21:48:01.250391","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.394129Z","iopub.execute_input":"2023-04-17T03:46:55.394921Z","iopub.status.idle":"2023-04-17T03:46:55.402851Z","shell.execute_reply.started":"2023-04-17T03:46:55.394882Z","shell.execute_reply":"2023-04-17T03:46:55.401804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALID_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nprint('Dataset: {} training images, {} validation images, {} (unlabeled) test images'.format(\n    NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES, NUM_TEST_IMAGES))","metadata":{"papermill":{"duration":0.051209,"end_time":"2020-11-19T21:48:01.396198","exception":false,"start_time":"2020-11-19T21:48:01.344989","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.404214Z","iopub.execute_input":"2023-04-17T03:46:55.404602Z","iopub.status.idle":"2023-04-17T03:46:55.419469Z","shell.execute_reply.started":"2023-04-17T03:46:55.404569Z","shell.execute_reply":"2023-04-17T03:46:55.418202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 简要的探索性数据分析 (EDA)\n首先，我们将打印出三个数据集的每个样本的形状和标签:","metadata":{"papermill":{"duration":0.041086,"end_time":"2020-11-19T21:48:01.478205","exception":false,"start_time":"2020-11-19T21:48:01.437119","status":"completed"},"tags":[]}},{"cell_type":"code","source":"print(\"Training data shapes:\")\nfor image, label in get_training_dataset().take(3):\n    print(image.numpy().shape, label.numpy().shape)\nprint(\"Training data label examples:\", label.numpy())\nprint(\"Validation data shapes:\")\nfor image, label in get_validation_dataset().take(3):\n    print(image.numpy().shape, label.numpy().shape)\nprint(\"Validation data label examples:\", label.numpy())\nprint(\"Test data shapes:\")\nfor image, idnum in get_test_dataset().take(3):\n    print(image.numpy().shape, idnum.numpy().shape)\nprint(\"Test data IDs:\", idnum.numpy().astype('U')) # U=unicode string","metadata":{"papermill":{"duration":17.07767,"end_time":"2020-11-19T21:48:18.597304","exception":false,"start_time":"2020-11-19T21:48:01.519634","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:46:55.421137Z","iopub.execute_input":"2023-04-17T03:46:55.421674Z","iopub.status.idle":"2023-04-17T03:47:05.352567Z","shell.execute_reply.started":"2023-04-17T03:46:55.421636Z","shell.execute_reply":"2023-04-17T03:47:05.350293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"下面的代码块设置了一系列函数，这些函数将打印出一个图像网格。图像网格将包含图像及其对应的标签。","metadata":{"papermill":{"duration":0.044101,"end_time":"2020-11-19T21:48:18.6862","exception":false,"start_time":"2020-11-19T21:48:18.642099","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Numpy和matplotlib默认值\nnp.set_printoptions(threshold=15, linewidth=80)\n\ndef batch_to_numpy_images_and_labels(data):\n    images, labels = data\n    numpy_images = images.numpy()\n    numpy_labels = labels.numpy()\n    if numpy_labels.dtype == object: # 二进制字符串，在这里，这些是图像ID字符串\n        numpy_labels = [None for _ in enumerate(numpy_images)]\n    # 如果没有标签，只有图像id，标签返回None(测试数据就是这样)\n    return numpy_images, numpy_labels\n\ndef title_from_label_and_target(label, correct_label):\n    if correct_label is None:\n        return CLASSES[label], True\n    correct = (label == correct_label)\n    return \"{} [{}{}{}]\".format(CLASSES[label], 'OK' if correct else 'NO', u\"\\u2192\" if not correct else '',\n                                CLASSES[correct_label] if not correct else ''), correct\n\ndef display_one_plant(image, title, subplot, red=False, titlesize=16):\n    plt.subplot(*subplot)\n    plt.axis('off')\n    plt.imshow(image)\n    if len(title) > 0:\n        plt.title(title, fontsize=int(titlesize) if not red else int(titlesize/1.2), color='red' if red else 'black', fontdict={'verticalalignment':'center'}, pad=int(titlesize/1.5))\n    return (subplot[0], subplot[1], subplot[2]+1)\n\ndef display_batch_of_images(databatch, predictions=None):\n    \"\"\"This will work with:\n    display_batch_of_images(images)\n    display_batch_of_images(images, predictions)\n    display_batch_of_images((images, labels))\n    display_batch_of_images((images, labels), predictions)\n    \"\"\"\n    # data\n    images, labels = batch_to_numpy_images_and_labels(databatch)\n    if labels is None:\n        labels = [None for _ in enumerate(images)]\n        \n    # 自动平方:这将删除不适合正方形或近似正方形的矩形的数据\n    rows = int(math.sqrt(len(images)))\n    cols = len(images)//rows\n        \n    # 列宽和列间距\n    FIGSIZE = 13.0\n    SPACING = 0.1\n    subplot=(rows,cols,1)\n    if rows < cols:\n        plt.figure(figsize=(FIGSIZE,FIGSIZE/cols*rows))\n    else:\n        plt.figure(figsize=(FIGSIZE/rows*cols,FIGSIZE))\n    \n    # display\n    for i, (image, label) in enumerate(zip(images[:rows*cols], labels[:rows*cols])):\n        title = '' if label is None else CLASSES[label]\n        correct = True\n        if predictions is not None:\n            title, correct = title_from_label_and_target(predictions[i], label)\n        dynamic_titlesize = FIGSIZE*SPACING/max(rows,cols)*40+3 # 魔术公式测试工作从1x1到10x10图像\n        subplot = display_one_plant(image, title, subplot, not correct, titlesize=dynamic_titlesize)\n    \n    #layout\n    plt.tight_layout()\n    if label is None and predictions is None:\n        plt.subplots_adjust(wspace=0, hspace=0)\n    else:\n        plt.subplots_adjust(wspace=SPACING, hspace=SPACING)\n    plt.show()","metadata":{"papermill":{"duration":0.077342,"end_time":"2020-11-19T21:48:18.808133","exception":false,"start_time":"2020-11-19T21:48:18.730791","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:05.355036Z","iopub.execute_input":"2023-04-17T03:47:05.355677Z","iopub.status.idle":"2023-04-17T03:47:05.384088Z","shell.execute_reply.started":"2023-04-17T03:47:05.355615Z","shell.execute_reply":"2023-04-17T03:47:05.381782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 加载EDA的训练数据集\ntraining_dataset = get_training_dataset()\ntraining_dataset = training_dataset.unbatch().batch(20)\ntrain_batch = iter(training_dataset)","metadata":{"papermill":{"duration":0.104176,"end_time":"2020-11-19T21:48:18.957003","exception":false,"start_time":"2020-11-19T21:48:18.852827","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:05.389803Z","iopub.execute_input":"2023-04-17T03:47:05.391049Z","iopub.status.idle":"2023-04-17T03:47:05.475784Z","shell.execute_reply.started":"2023-04-17T03:47:05.390939Z","shell.execute_reply":"2023-04-17T03:47:05.474611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 再次运行此单元格以获得另一组随机训练图像\ndisplay_batch_of_images(next(train_batch))","metadata":{"papermill":{"duration":3.371477,"end_time":"2020-11-19T21:48:22.374778","exception":false,"start_time":"2020-11-19T21:48:19.003301","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:05.477504Z","iopub.execute_input":"2023-04-17T03:47:05.478208Z","iopub.status.idle":"2023-04-17T03:47:08.652994Z","shell.execute_reply.started":"2023-04-17T03:47:05.478169Z","shell.execute_reply":"2023-04-17T03:47:08.651666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"你也可以修改上面的代码来查看你的“验证”和“测试”数据，就像这样:","metadata":{"papermill":{"duration":0.086379,"end_time":"2020-11-19T21:48:22.547481","exception":false,"start_time":"2020-11-19T21:48:22.461102","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# 加载EDA的验证数据集\nvalidation_dataset = get_validation_dataset()\nvalidation_dataset = validation_dataset.unbatch().batch(20)\nvalid_batch = iter(validation_dataset)","metadata":{"papermill":{"duration":0.136485,"end_time":"2020-11-19T21:48:22.769878","exception":false,"start_time":"2020-11-19T21:48:22.633393","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:08.654745Z","iopub.execute_input":"2023-04-17T03:47:08.655114Z","iopub.status.idle":"2023-04-17T03:47:08.712322Z","shell.execute_reply.started":"2023-04-17T03:47:08.655077Z","shell.execute_reply":"2023-04-17T03:47:08.711060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 再次运行此单元格以获得另一组随机训练图像\ndisplay_batch_of_images(next(valid_batch))","metadata":{"papermill":{"duration":3.155802,"end_time":"2020-11-19T21:48:26.010993","exception":false,"start_time":"2020-11-19T21:48:22.855191","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:08.713580Z","iopub.execute_input":"2023-04-17T03:47:08.714606Z","iopub.status.idle":"2023-04-17T03:47:11.425325Z","shell.execute_reply.started":"2023-04-17T03:47:08.714538Z","shell.execute_reply":"2023-04-17T03:47:11.424185Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 加载EDA的测试数据集\ntesting_dataset = get_test_dataset()\ntesting_dataset = testing_dataset.unbatch().batch(20)\ntest_batch = iter(testing_dataset)","metadata":{"papermill":{"duration":0.232531,"end_time":"2020-11-19T21:48:26.411209","exception":false,"start_time":"2020-11-19T21:48:26.178678","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:11.427047Z","iopub.execute_input":"2023-04-17T03:47:11.428131Z","iopub.status.idle":"2023-04-17T03:47:11.478708Z","shell.execute_reply.started":"2023-04-17T03:47:11.428022Z","shell.execute_reply":"2023-04-17T03:47:11.477415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 我们只有一个测试图像\ndisplay_batch_of_images(next(test_batch))","metadata":{"papermill":{"duration":1.333241,"end_time":"2020-11-19T21:48:27.900651","exception":false,"start_time":"2020-11-19T21:48:26.56741","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:11.480211Z","iopub.execute_input":"2023-04-17T03:47:11.480765Z","iopub.status.idle":"2023-04-17T03:47:13.539936Z","shell.execute_reply.started":"2023-04-17T03:47:11.480724Z","shell.execute_reply":"2023-04-17T03:47:13.538910Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 建立模型\n## 学习率表\n我们在深度学习入门:随机梯度下降课程中了解了学习率，在这里我主要使用Keras指数衰减学习率调度器文档中的默认值创建了一个学习率计划(我确实更改了initial_learning_rate。您可以在下面调整学习率调度器，并在Keras学习率调度器API中阅读更多关于其他类型的调度器的信息。","metadata":{"papermill":{"duration":0.230199,"end_time":"2020-11-19T21:48:28.353794","exception":false,"start_time":"2020-11-19T21:48:28.123595","status":"completed"},"tags":[]}},{"cell_type":"code","source":"lr_scheduler = keras.optimizers.schedules.ExponentialDecay(\n    initial_learning_rate=1e-5, \n    decay_steps=10000, \n    decay_rate=0.9)","metadata":{"papermill":{"duration":0.248904,"end_time":"2020-11-19T21:48:28.83328","exception":false,"start_time":"2020-11-19T21:48:28.584376","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:13.541232Z","iopub.execute_input":"2023-04-17T03:47:13.542172Z","iopub.status.idle":"2023-04-17T03:47:13.548039Z","shell.execute_reply.started":"2023-04-17T03:47:13.542129Z","shell.execute_reply":"2023-04-17T03:47:13.546523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Building our model\n为了确保我们的模型是在TPU上训练的，我们使用“with strategy.scope()”来构建它。    \n\n这个模型是使用迁移学习构建的，这意味着我们有一个预先训练好的模型(ResNet50)作为我们的基础模型，然后使用tf.keras.Sequential构建可定制的模型。如果你是迁移学习的新手，我建议你设置base_model。可训练为False，但鼓励你改变你正在使用的基本模型(在tf.keras.applications Module文档中有更多选项)以及迭代自定义模型。\n\n注意，我们使用sparse_categorical_crossentropy作为损失函数，因为我们没有对标签进行one-hot encode编码。 ","metadata":{"papermill":{"duration":0.22538,"end_time":"2020-11-19T21:48:29.285377","exception":false,"start_time":"2020-11-19T21:48:29.059997","status":"completed"},"tags":[]}},{"cell_type":"code","source":"with strategy.scope():       \n    img_adjust_layer = tf.keras.layers.Lambda(tf.keras.applications.resnet50.preprocess_input, input_shape=[*IMAGE_SIZE, 3])\n    \n    base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)\n    base_model.trainable = False\n    \n    model = tf.keras.Sequential([\n        tf.keras.layers.BatchNormalization(renorm=True),\n        img_adjust_layer,\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(8, activation='relu'),\n        #tf.keras.layers.BatchNormalization(renorm=True),\n        tf.keras.layers.Dense(len(CLASSES), activation='softmax')  \n    ])\n    \n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=lr_scheduler, epsilon=0.001),\n        loss='sparse_categorical_crossentropy',  \n        metrics=['sparse_categorical_accuracy'])","metadata":{"papermill":{"duration":19.661572,"end_time":"2020-11-19T21:48:49.158413","exception":false,"start_time":"2020-11-19T21:48:29.496841","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:13.550233Z","iopub.execute_input":"2023-04-17T03:47:13.550681Z","iopub.status.idle":"2023-04-17T03:47:36.388564Z","shell.execute_reply.started":"2023-04-17T03:47:13.550636Z","shell.execute_reply":"2023-04-17T03:47:36.387488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train the model\n当我们的模型正在训练时，您将看到每个纪元的打印输出，也可以通过单击笔记本右上方工具栏中的TPU指标来监控TPU使用情况。","metadata":{"papermill":{"duration":0.174404,"end_time":"2020-11-19T21:48:49.513099","exception":false,"start_time":"2020-11-19T21:48:49.338695","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# load data\ntrain_dataset = get_training_dataset()\nvalid_dataset = get_validation_dataset()","metadata":{"papermill":{"duration":0.249051,"end_time":"2020-11-19T21:48:49.936435","exception":false,"start_time":"2020-11-19T21:48:49.687384","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:36.389886Z","iopub.execute_input":"2023-04-17T03:47:36.390238Z","iopub.status.idle":"2023-04-17T03:47:36.486344Z","shell.execute_reply.started":"2023-04-17T03:47:36.390202Z","shell.execute_reply":"2023-04-17T03:47:36.484921Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\nVALID_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE\n\nhistory = model.fit(train_dataset, \n                    steps_per_epoch=STEPS_PER_EPOCH, \n                    epochs=EPOCHS,\n                    validation_data=valid_dataset,\n                    validation_steps=VALID_STEPS)","metadata":{"papermill":{"duration":956.681695,"end_time":"2020-11-19T22:04:46.795744","exception":false,"start_time":"2020-11-19T21:48:50.114049","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T03:47:36.488280Z","iopub.execute_input":"2023-04-17T03:47:36.488665Z","iopub.status.idle":"2023-04-17T04:01:36.704606Z","shell.execute_reply.started":"2023-04-17T03:47:36.488630Z","shell.execute_reply":"2023-04-17T04:01:36.702491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"使用model.summary()，我们将看到每个层的打印输出、它们对应的形状以及相关的参数数量。请注意，在打印输出的底部，我们将看到关于总参数、可训练参数和不可训练参数的信息。因为我们使用的是一个预训练的模型，所以我们预计会有大量不可训练的参数(因为权重已经在预训练的模型中分配了)。","metadata":{"papermill":{"duration":1.26977,"end_time":"2020-11-19T22:04:49.3763","exception":false,"start_time":"2020-11-19T22:04:48.10653","status":"completed"},"tags":[]}},{"cell_type":"code","source":"model.summary()","metadata":{"papermill":{"duration":1.344562,"end_time":"2020-11-19T22:04:51.988755","exception":false,"start_time":"2020-11-19T22:04:50.644193","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:36.711441Z","iopub.execute_input":"2023-04-17T04:01:36.712199Z","iopub.status.idle":"2023-04-17T04:01:36.798104Z","shell.execute_reply.started":"2023-04-17T04:01:36.712133Z","shell.execute_reply":"2023-04-17T04:01:36.796497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 评估我们的模型\n第一个代码块用于显示第二个代码块中的变量来自何处。正如你所看到的，这个模型还有很大的改进空间，但因为我们使用的是tpu，而且训练时间相对较短，所以我们能够相当快速地迭代我们的模型。","metadata":{"papermill":{"duration":1.245239,"end_time":"2020-11-19T22:04:54.493139","exception":false,"start_time":"2020-11-19T22:04:53.2479","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# 打印出我们可用的变量\nprint(history.history.keys())","metadata":{"papermill":{"duration":1.31245,"end_time":"2020-11-19T22:04:57.054025","exception":false,"start_time":"2020-11-19T22:04:55.741575","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:36.800786Z","iopub.execute_input":"2023-04-17T04:01:36.801473Z","iopub.status.idle":"2023-04-17T04:01:36.809285Z","shell.execute_reply.started":"2023-04-17T04:01:36.801410Z","shell.execute_reply":"2023-04-17T04:01:36.807221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 创建学习曲线以评估模型性能\nhistory_frame = pd.DataFrame(history.history)\nhistory_frame.loc[:, ['loss', 'val_loss']].plot()\nhistory_frame.loc[:, ['sparse_categorical_accuracy', 'val_sparse_categorical_accuracy']].plot();","metadata":{"papermill":{"duration":1.671861,"end_time":"2020-11-19T22:04:59.983272","exception":false,"start_time":"2020-11-19T22:04:58.311411","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:36.819691Z","iopub.execute_input":"2023-04-17T04:01:36.820380Z","iopub.status.idle":"2023-04-17T04:01:37.604121Z","shell.execute_reply.started":"2023-04-17T04:01:36.820304Z","shell.execute_reply":"2023-04-17T04:01:37.602226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 做出预测\n现在我们已经训练了我们的模型，我们可以用它来进行预测!","metadata":{"papermill":{"duration":1.326243,"end_time":"2020-11-19T22:05:02.628032","exception":false,"start_time":"2020-11-19T22:05:01.301789","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# 这段代码将把我们的测试图像数据转换为float32\ndef to_float32(image, label):\n    return tf.cast(image, tf.float32), label","metadata":{"papermill":{"duration":1.270192,"end_time":"2020-11-19T22:05:05.187694","exception":false,"start_time":"2020-11-19T22:05:03.917502","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:37.606479Z","iopub.execute_input":"2023-04-17T04:01:37.608350Z","iopub.status.idle":"2023-04-17T04:01:37.617226Z","shell.execute_reply.started":"2023-04-17T04:01:37.608160Z","shell.execute_reply":"2023-04-17T04:01:37.614758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = get_test_dataset(ordered=True) \ntest_ds = test_ds.map(to_float32)\n\nprint('Computing predictions...')\ntest_images_ds = testing_dataset\ntest_images_ds = test_ds.map(lambda image, idnum: image)\nprobabilities = model.predict(test_images_ds)\npredictions = np.argmax(probabilities, axis=-1)\nprint(predictions)","metadata":{"papermill":{"duration":15.776858,"end_time":"2020-11-19T22:05:22.235661","exception":false,"start_time":"2020-11-19T22:05:06.458803","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:37.619973Z","iopub.execute_input":"2023-04-17T04:01:37.621210Z","iopub.status.idle":"2023-04-17T04:01:49.177217Z","shell.execute_reply.started":"2023-04-17T04:01:37.621138Z","shell.execute_reply":"2023-04-17T04:01:49.175066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 创建提交文件\n现在我们已经训练了一个模型并做出了预测，我们准备好提交给比赛了!您可以运行下面的代码来获取您的提交文件。","metadata":{"papermill":{"duration":1.271799,"end_time":"2020-11-19T22:05:24.759257","exception":false,"start_time":"2020-11-19T22:05:23.487458","status":"completed"},"tags":[]}},{"cell_type":"code","source":"print('Generating submission.csv file...')\ntest_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\ntest_ids = next(iter(test_ids_ds.batch(NUM_TEST_IMAGES))).numpy().astype('U') # all in one batch\nnp.savetxt('submission.csv', np.rec.fromarrays([test_ids, predictions]), fmt=['%s', '%d'], delimiter=',', header='id,label', comments='')\n!head submission.csv","metadata":{"papermill":{"duration":2.185537,"end_time":"2020-11-19T22:05:28.241723","exception":false,"start_time":"2020-11-19T22:05:26.056186","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-04-17T04:01:49.179556Z","iopub.execute_input":"2023-04-17T04:01:49.180258Z","iopub.status.idle":"2023-04-17T04:01:50.575297Z","shell.execute_reply.started":"2023-04-17T04:01:49.180199Z","shell.execute_reply":"2023-04-17T04:01:50.572899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"请注意，因为这是一个带有隐藏测试集的代码竞赛，所以不能在您的提交笔记本上启用internet和tpu。因此tpu将只用于训练模型。有关如何在TPU上训练和在gpu上运行推理/提交的演练，请参阅我们的TPU文档。 [TPU Docs](https://www.kaggle.com/docs/tpu#tpu6).","metadata":{"papermill":{"duration":1.255302,"end_time":"2020-11-19T22:05:30.746339","exception":false,"start_time":"2020-11-19T22:05:29.491037","status":"completed"},"tags":[]}}]}