MLOps- 吴恩达Andrew Ng Selecting and Training a Model Week2 实验作业

Posted 架构师易筋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MLOps- 吴恩达Andrew Ng Selecting and Training a Model Week2 实验作业相关的知识,希望对你有一定的参考价值。

第 2 周 - 未分级实验室:数据之旅

欢迎来到生产机器学习工程第 2 周的未分级实验室。深度学习背后的范式现在正面临从以模型为中心到以数据为中心的转变。在本实验中,您将看到复杂的数据如何影响模型的结果。为了向您展示在不解决模型的情况下应用数据更改需要多远,您将始终使用一个模型:一个简单的卷积神经网络 (CNN)。在训练这个模型的过程中,你将解决一些常见问题:类不平衡和过度拟合。在您解决这些问题时,实验室将引导您了解有用的诊断工具和方法,以缓解这些常见问题。

开始实验室前的重要注意事项

在 Colab 中打开后,单击屏幕右上角的“连接”按钮以连接到运行时以运行此实验室。

注 1:

在本实验中,您可以选择自己训练模型(这大约需要 20 分钟,为每个模型启用 GPU)或使用已经提供的预训练版本。总共有 3 个 CNN 需要训练,尽管已经调整了一些参数以提供更快的训练时间(例如steps_per_epoch和validation_steps已大幅降低),但这可能会导致运行此实验室花费很长时间,而不是考虑您观察。

为了加快速度,我们提供了每个模型的已保存预训练版本及其各自的训练历史。我们建议您使用这些预先训练的版本以节省时间。但是,我们也认为训练模型是一种重要的学习体验,尤其是如果您以前没有这样做过的话。如果你想自己进行这个训练,也提供了复制训练的代码。在这种情况下,GPU 是绝对必要的,因此请确保启用它。

要确保您的运行时是 GPU,您可以转到运行时 -> 更改运行时类型 -> 从菜单中选择 GPU,然后按保存

注意:可能需要重新启动运行时。

Colab 会告诉您是否需要重新启动——您可以从下拉菜单中的运行时 -> 重新启动运行时选项中执行此操作。

如果您决定使用预训练版本,请确保您没有使用 GPU,因为它不是必需的,并且可能会阻止其他用户访问 GPU。要检查这一点,请转到运行时 -> 更改运行时类型 -> 从菜单中选择无,然后按保存。

笔记2:

Colab不保证对 GPU 的访问。这取决于这些资源的可用性。然而,GPU 访问被拒绝的情况并不常见。如果您遇到这种情况,您仍然可以运行此实验室,而无需自己训练模型。如果您真的想进行训练但被拒绝使用 GPU,请尝试在几个小时后将运行时切换到 GPU。

要了解有关 Colab 政策的更多信息,请查看此常见问题解答。

开始实验

import os
import shutil
import random
import zipfile
import tarfile
import numpy as np
import pandas as pd
import seaborn as sns
import tensorflow as tf
import matplotlib.pyplot as plt

# To ignore some warnings about Image metadata that Pillow prints out
import warnings
warnings.filterwarnings("ignore")

在继续之前,下载实验室中使用的两个数据集,以及预训练的模型和历史:

# Download datasets

# Cats and dogs
!wget https://storage.googleapis.com/mlep-public/course_1/week2/kagglecatsanddogs_3367a.zip

# Caltech birds
!wget https://storage.googleapis.com/mlep-public/course_1/week2/CUB_200_2011.tar

# Download pretrained models and training histories
!wget -q -P /content/model-balanced/ https://storage.googleapis.com/mlep-public/course_1/week2/model-balanced/saved_model.pb
!wget -q -P /content/model-balanced/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-balanced/variables/variables.data-00000-of-00001
!wget -q -P /content/model-balanced/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-balanced/variables/variables.index
!wget -q -P /content/history-balanced/ https://storage.googleapis.com/mlep-public/course_1/week2/history-balanced/history-balanced.csv

!wget -q -P /content/model-imbalanced/ https://storage.googleapis.com/mlep-public/course_1/week2/model-imbalanced/saved_model.pb
!wget -q -P /content/model-imbalanced/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-imbalanced/variables/variables.data-00000-of-00001
!wget -q -P /content/model-imbalanced/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-imbalanced/variables/variables.index
!wget -q -P /content/history-imbalanced/ https://storage.googleapis.com/mlep-public/course_1/week2/history-imbalanced/history-imbalanced.csv

!wget -q -P /content/model-augmented/ https://storage.googleapis.com/mlep-public/course_1/week2/model-augmented/saved_model.pb
!wget -q -P /content/model-augmented/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-augmented/variables/variables.data-00000-of-00001
!wget -q -P /content/model-augmented/variables/ https://storage.googleapis.com/mlep-public/course_1/week2/model-augmented/variables/variables.index
!wget -q -P /content/history-augmented/ https://storage.googleapis.com/mlep-public/course_1/week2/history-augmented/history-augmented.csv

1. 一个数据故事

为了引导您完成本实验,我们准备了一个模拟真实生活场景的叙述:

假设您的任务是创建一个模型来对猫、狗和鸟的图像进行分类。为此,您选择了一个简单的 CNN 架构,因为众所周知 CNN 在图像分类方面表现良好。您可能熟悉两个广泛使用的数据集:cats vs dogs, 和caltech birds。作为旁注,这两个数据集都可以通过Tensforflow Datasets (TFDS). 但是,您决定不使用,TFDS因为实验室要求您修改数据并将两个数据集合并为一个。

1.1 合并数据集

这些数据集中的原始图像可以在以下路径中找到:

cats_and_dogs_zip = '/content/kagglecatsanddogs_3367a.zip'
caltech_birds_tar = '/content/CUB_200_2011.tar'

base_dir = '/tmp/data'

base_dir在这种情况下,下一步是将数据提取到选择的目录中。

请注意,cats vs dogs图像是在zip文件格式,而caltech birds图像来在tar文件中。

with zipfile.ZipFile(cats_and_dogs_zip, 'r') as my_zip:
  my_zip.extractall(base_dir)
with tarfile.open(caltech_birds_tar, 'r') as my_tar:
  my_tar.extractall(base_dir)

对于猫和狗的图像,不需要进一步的预处理,因为一个类的所有样本都位于一个目录中:PetImages\\Cat和PetImages\\Dog。让我们检查每个类别有多少图像可用:

base_dogs_dir = os.path.join(base_dir, 'PetImages/Dog')
base_cats_dir = os.path.join(base_dir,'PetImages/Cat')

print(f"There are {len(os.listdir(base_dogs_dir))} images of dogs")
print(f"There are {len(os.listdir(base_cats_dir))} images of cats")

Bird 图像数据集组织完全不同。该数据集通常用于对鸟类进行分类,因此每个物种都有一个目录。让我们将所有种类的鸟类视为一个类。这需要将所有鸟类图像移动到一个目录(PetImages/Bird将用于一致性)。这可以通过运行下一个单元格来完成:

raw_birds_dir = '/tmp/data/CUB_200_2011/images'
base_birds_dir = os.path.join(base_dir,'PetImages/Bird')
os.mkdir(base_birds_dir)

for subdir in os.listdir(raw_birds_dir):
  subdir_path = os.path.join(raw_birds_dir, subdir)
  for image in os.listdir(subdir_path):
    shutil.move(os.path.join(subdir_path, image), os.path.join(base_birds_dir))

print(f"There are {len(os.listdir(base_birds_dir))} images of birds")

事实证明,您尝试预测的每个类都有相似数量的图像!好的!

让我们快速浏览一下您尝试预测的每个类的图像。

from IPython.display import Image, display

print("Sample cat image:")
display(Image(filename=f"{os.path.join(base_cats_dir, os.listdir(base_cats_dir)[0])}"))
print("\\nSample dog image:")
display(Image(filename=f"{os.path.join(base_dogs_dir, os.listdir(base_dogs_dir)[0])}"))
print("\\nSample bird image:")
display(Image(filename=f"{os.path.join(base_birds_dir, os.listdir(base_birds_dir)[0])}"))

2. 训练/评估拆分

在训练模型之前,您需要将数据拆分为training和evaluating集合。对于培训,我们选择了Keras应用程序编程接口 (API),其中包括从各种目录读取图像的功能。拆分数据的更简单方法是为每个类的每个拆分创建一个不同的目录。

运行下一个单元格以创建用于训练和评估集的目录。

train_eval_dirs = ['train/cats', 'train/dogs', 'train/birds',
                   'eval/cats', 'eval/dogs', 'eval/birds']

for dir in train_eval_dirs:
  if not os.path.exists(os.path.join(base_dir, dir)):
    os.makedirs(os.path.join(base_dir, dir))

现在,让我们定义一个函数,根据需要将一定比例的图像从原始文件夹移动到目标文件夹以生成训练和评估拆分:

def move_to_destination(origin, destination, percentage_split):
  num_images = int(len(os.listdir(origin))*percentage_split)
  for image_name, image_number in zip(sorted(os.listdir(origin)), range(num_images)):
    shutil.move(os.path.join(origin, image_name), destination)

现在您已准备好调用前一个函数并拆分数据:

# Move 70% of the images to the train dir
move_to_destination(base_cats_dir, os.path.join(base_dir, 'train/cats'), 0.7)
move_to_destination(base_dogs_dir, os.path.join(base_dir, 'train/dogs'), 0.7)
move_to_destination(base_birds_dir, os.path.join(base_dir, 'train/birds'), 0.7)


# Move the remaining images to the eval dir
move_to_destination(base_cats_dir, os.path.join(base_dir, 'eval/cats'), 1)
move_to_destination(base_dogs_dir, os.path.join(base_dir, 'eval/dogs'), 1)
move_to_destination(base_birds_dir, os.path.join(base_dir, 'eval/birds'), 1)

值得一提的是,就目前而言,您的数据集存在一些问题,会阻止模型训练和评估。主要是:

  1. 某些图像已损坏且字节数为零。
  2. Cats vs Dogs zip 文件包含.db需要删除的每个类的文件。

如果您在培训前未解决此问题,您将收到有关这些问题的错误,并且培训将失败。零字节图像不是有效图像,一旦到达这些文件,Keras 会通知您。以类似的方式.db文件不是有效的图像。在开始运行之前始终确保向训练算法提交具有正确规范的文件是一个很好的做法,因为这些问题可能不会立即遇到,您将不得不解决它们并重新开始训练。

bash在基本目录中运行以下命令将解决这些问题:

!find /tmp/data/ -size 0 -exec rm {} +
!find /tmp/data/ -type f ! -name "*.jpg" -exec rm {} +

第一个命令从文件系统中删除所有零字节文件。第二个删除任何没有.jpg扩展名的文件。

这也提醒人们 bash 的力量。尽管您可以使用 Python 代码实现相同的结果,但 bash 允许您更快地完成此操作。如果您不熟悉 bash 或其他类似 shell 的语言,我们鼓励您学习其中的一些,因为它是用于数据操作的非常有用的工具。

在删除损坏的图像后,让我们检查一下每个拆分和类有多少可用图像:

print(f"There are {len(os.listdir(os.path.join(base_dir, 'train/cats')))} images of cats for training")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'train/dogs')))} images of dogs for training")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'train/birds')))} images of birds for training\\n")

print(f"There are {len(os.listdir(os.path.join(base_dir, 'eval/cats')))} images of cats for evaluation")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'eval/dogs')))} images of dogs for evaluation")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'eval/birds')))} images of birds for evaluation")

事实证明,很少有文件提出了上述问题。这是个好消息,但它也提醒我们,数据集的小问题可能会意外地影响训练过程。在这种情况下,4 个无效的图像文件将阻止您训练模型。

在大多数情况下,训练深度学习模型是一项耗时的任务,因此在开始此过程之前一定要准备好一切。

3. 一个意想不到的问题!

让我们面对这个故事中的第一个现实生活问题!有你的办公室停电和一些硬盘驱动器被损坏,并作为其中的一个结果是,许多的图像dogs,并birds已被删除。事实上,只有 20% 的狗图像和 10% 的鸟图像幸存下来。

为了模拟这种情况,让我们快速创建一个名为的新目录,imbalanced并仅为每个类复制上面提到的比例。

for dir in train_eval_dirs:
  if not os.path.exists(os.path.join(base_dir, 'imbalanced/'+dir)):
    os.makedirs(os.path.join(base_dir, 'imbalanced/'+dir))
# Very similar to the one used before but this one copies instead of moving
def copy_with_limit(origin, destination, percentage_split):
  num_images = int(len(os.listdir(origin))*percentage_split)
  for image_name, image_number in zip(sorted(os.listdir(origin)), range(num_images)):
    shutil.copy(os.path.join(origin, image_name), destination)

# Perform the copying
copy_with_limit(os.path.join(base_dir, 'train/cats'), os.path.join(base_dir, 'imbalanced/train/cats'), 1)
copy_with_limit(os.path.join(base_dir, 'train/dogs'), os.path.join(base_dir, 'imbalanced/train/dogs'), 0.2)
copy_with_limit(os.path.join(base_dir, 'train/birds'), os.path.join(base_dir, 'imbalanced/train/birds'), 0.1)

copy_with_limit(os.path.join(base_dir, 'eval/cats'), os.path.join(base_dir, 'imbalanced/eval/cats'), 1)
copy_with_limit(os.path.join(base_dir, 'eval/dogs'), os.path.join(base_dir, 'imbalanced/eval/dogs'), 0.2)
copy_with_limit(os.path.join(base_dir, 'eval/birds'), os.path.join(base_dir, 'imbalanced/eval/birds'), 0.1)

# Print number of available images
print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/train/cats')))} images of cats for training")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/train/dogs')))} images of dogs for training")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/train/birds')))} images of birds for training\\n")

print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/eval/cats')))} images of cats for evaluation")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/eval/dogs')))} images of dogs for evaluation")
print(f"There are {len(os.listdir(os.path.join(base_dir, 'imbalanced/eval/birds')))} images of birds for evaluation")

对于意外文件丢失,目前没有快速或明确的解决方案。因此,您决定继续使用剩余图像训练模型。

3.1 选择型号

让我们继续创建模型架构,并利用 keras API 定义损失函数、优化器和性能指标:

from tensorflow.keras import layers, models, optimizers

def create_model():
  # A simple CNN architecture based on the one found here: https://www.tensorflow.org/tutorials/images/classification
  model = models.Sequential([
  layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)),
  layers.MaxPooling2D((2, 2)),
  layers.Conv2D(64, (3, 3), activation='relu'),
  layers.MaxPooling2D((2, 2)),
  layers.Conv2D(64, (3, 3), activation='relu'),
  layers.MaxPooling2D((2, 2)),
  layers.Conv2D(128, (3, 3), activation='relu'),
  layers.MaxPooling2D((2, 2)),
  layers.Flatten(),
  layers.Dense(512, activation='relu'),
  layers.Dense(3, activation='softmax')
  ])


  # Compile the model
  modelMLOps- 吴恩达Andrew Ng Selecting and Training a Model Week2 论文等资料汇总

MLOps- 吴恩达Andrew Ng Overview of the ML Lifecycle and Deployment Week1 论文等资料汇总

MLOps- 吴恩达Andrew Ng Data Definition and Baseline Week3 实验作业

MLOps- 吴恩达Andrew Ng Selecting and Training a Model Week2 实验作业

MLOps- 吴恩达Andrew Ng Overview of the ML Lifecycle and Deployment Week1 部署深度学习模型model 实现

Andrew Ng 吴恩达近期论文整理