机器之心编译作者:Cameron Cruz

TensorFlow 2.0到底怎么样?简单的图像分类任务探一探

一个月前,谷歌在 Tensorflow Developer Summit 2019 大会上发布 TensorFlow 2.0 Alpha 版。那么使用 TF 2.0 写模型到底是一种什么样的体验?在这篇文章中,我们将介绍如何用 TF 2.0 打造一个简单的图像分类模型,虽然任务很简单,但它们展示了 TensorFlow 将来的新特性。

好处多多的新版本

从历史角度看,TensorFlow机器学习框架的「工业车床」:具有复杂性和陡峭学习曲线的强大工具。如果你之前用过 TensorFlow 1.x,你就会知道复杂与难用是在说什么。

2.0 版本体现了开发人员在改善 TensorFlow 可用性、简洁性和灵活性方面所做出的努力,亮点如下:

  • 在不牺牲基于图形的执行的性能优化情况下,默认情况下启用实时执行(Eager Execution);

  • API 更简洁、更一致,也更少冗余;

  • 更紧密地集成了 Keras 作为高级 API;

  • 其他(https://www.tensorflow.org/community/roadmap)。

因此,TensorFlow 2.0 更 Python 化(Pythonic),而且学习起来不那么困难,如果你需要的话,还可以保留较底层的自定义和复杂性。接下来我们要用 TensorFLow 2.0 研究如何在经典的图像分类中应用其高级 API。

在 Colab 上安装 TensorFlow 2.0 Alpha 

谷歌 Colaboratory 可以轻易地在云上设置 Python 笔记本。Colab 可以免费使用 GPU 12 小时,因此我一般都将它作为我进行机器学习实验的首选平台。

用 pip 在 Colab 笔记本上安装 TensorFlow 2.0 Alpha(内测版)GPU 版:

!pip install tensorflow-gpu==2.0.0-alpha0

检查是否正确安装了 TensorFlow 2.0:

import tensorflow as tf

print(tf.__version)
# Output: 2.0.0-alpha0

你应该可以正常运行了!如果运行时遇到了问题,请在 Edit>Notebook 的设置中仔细检查 Colab 运行时是否用「GPU」作为运行时加速器。

用 tf.data.Dataset 加载数据

我们用的是 Kaggle 的 Aerial Cactus Identification(仙人掌航拍识别)竞赛(https://www.kaggle.com/c/aerial-cactus-identification)中的数据集。我们的任务是要建立可以分辨航拍图像中是否含有树状仙人掌的分类器。这是 Cactus Aerial Photos 数据集的修改版,Kaggle 将每张图的大小调整为 32*32 像素。

含有仙人掌的示例

没有仙人掌的示例(放大到 4 倍)

从 Kaggle 下载和解压数据集的代码,请参阅:https://github.com/cameroncruz/notebooks/blob/master/Easy_Image_Classification_with_TF_2.ipynb

用 Pandas 将图像及对应标签加载到 DataFrame 结构中,然后用 sklearn.model_selection 按 9:1 的比例分割训练集和验证集

train_csv = pd.read_csv('data/train.csv')
# Prepend image filenames in train/ with relative path
filenames = ['train/' + fname for fname in train_csv['id'].tolist()]
labels = train_csv['has_cactus'].tolist()
train_filenames, val_filenames, train_labels, val_labels = 
  train_test_split(filenames,
                 labels,
                 train_size=0.9,
                 random_state=42)

现在我们已经将图像文件名和标签分成了训练集和验证集,可以分别创建相应的 tf.data.Dataset 对象了。

train_data = tf.data.Dataset.from_tensor_slices(
  (tf.constant(train_filenames), tf.constant(train_labels))
)
val_data = tf.data.Dataset.from_tensor_slices(
  (tf.constant(val_filenames), tf.constant(val_labels))
)

但我们的数据集现在只有图像的文件名,并没有实际图像。我们需要定义可以通过文件名加载图像并执行必要预处理的函数。在这个过程中还要打乱(shuffle)数据集,并对数据集进行分批处理(batch):

IMAGE_SIZE = 96 # Minimum image size for use with MobileNetV2
BATCH_SIZE = 32
# Function to load and preprocess each image
def _parse_fn(filename, label):
    img = tf.io.read_file(img)
    img = tf.image.decode_jpeg(img)
    img = (tf.cast(img, tf.float32)/127.5) - 1
    img = tf.image.resize(img, (IMAGE_SIZE, IMAGE_SIZE))
    return img, label

# Run _parse_fn over each example in train and val datasets
# Also shuffle and create batches
train_data = (train_data.map(_parse_fn)
             .shuffle(buffer_size=10000)
             .batch(BATCH_SIZE)
             )
val_data = (val_data.map(_parse_fn)
           .shuffle(buffer_size=10000)
           .batch(BATCH_SIZE)
           )

建立用于迁移学习的模型

迁移学习可以使用现有的预训练图像分类模型来加快训练速度,它只需要重新训练最后一个分类层,并借此确定图像所属类别即可。

迁移学习图解

现在我们能用 TensorFlow 2.0 的高级 Keras API 快速构建图像分类模型。因为用了迁移学习,我们可以用预训练的 MobileNetV2 模型作为特征检测器。MobileNetV2 是谷歌发布的第二代 MobileNet,其目标是比 ResNet 和 Inception 更小、更轻量级,并可以在移动设备上实时运行。加载在 ImageNet 上预训练且没有最上层的 MobileNetV2,固定其权重,并添加新的分类层:

IMG_SHAPE = (IMAGE_SIZE, IMAGE_SIZE, 3)
# Pre-trained model with MobileNetV2
base_model = tf.keras.applications.MobileNetV2(
    input_shape=IMG_SHAPE,
    include_top=False,
    weights='imagenet'
)
# Freeze the pre-trained model weights
base_model.trainable = False
# Trainable classification head
maxpool_layer = tf.keras.layers.GlobalMaxPooling2D()
prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')
# Layer classification head with feature detector
model = tf.keras.Sequential([
    base_model,
    maxpool_layer,
    prediction_layer
])
learning_rate = 0.0001
# Compile the model
model.compile(optimizer=tf.keras.optimizers.Adam(lr=learning_rate), 
              loss='binary_crossentropy',
              metrics=['accuracy']
)

注意,这里建议用 TensorFlow 优化器来训练 tf.keras 模型。在 TensorFlow 2.0 中,之前的 tf.train 和 tf.keras.optimizers API 中的优化器已经统一在 tf.keras.optimizers 中,并用升级的 TensorFlow 优化器代替了原来的 tf.keras 优化器。因此,用 TensorFlow 优化器现在成为了更简单也更一致的体验,它完全支持使用 tf.kears API,而且不会牺牲任何性能。

训练模型

TensorFlow 2.0 中的 tf.keras API 现在完全支持 tf.data API,所以训练模型时可以轻松使用 tf.data.Dataset。同样,在不牺牲基于图形的执行的性能优势的情况下,默认情况下会用 Eager Execution 进行训练。

num_epochs = 30
steps_per_epoch = round(num_train)//BATCH_SIZE
val_steps = 20
model.fit(train_data.repeat(),
          epochs=num_epochs,
          steps_per_epoch = steps_per_epoch,
          validation_data=val_data.repeat(), 
          validation_steps=val_steps)

30 个 epoch 后,模型的验证准确率从 0.63 上升到 0.94。

迁移学习 30 个 epoch 的准确率和损失。

模型的微调

接着我们试着进一步提高模型的准确率。当我们在使用迁移学习时,我们只要在固定 MobileNetV2 的情况下训练新的分类层即可。如果一开始没有固定权重,那模型会因新分类层的随机初始化而「忘掉」开始时所有的知识。不过既然我们已经先训练了分类层,那么我们就可以解除对预训练层级的固定,从而根据特定的数据集对模型进行微调。

# Unfreeze all layers of MobileNetV2
base_model.trainable = True

# Refreeze layers until the layers we want to fine-tune
for layer in base_model.layers[:100]:
  layer.trainable =  False
# Use a lower learning rate
lr_finetune = learning_rate / 10
# Recompile the model
model.compile(loss='binary_crossentropy',
              optimizer = tf.keras.optimizers.Adam(lr=lr_finetune),
              metrics=['accuracy'])
# Increase training epochs for fine-tuning
fine_tune_epochs = 30
total_epochs =  num_epochs + fine_tune_epochs

# Fine-tune model
# Note: Set initial_epoch to begin training after epoch 30 since we
# previously trained for 30 epochs.
model.fit(train_data.repeat(), 
          steps_per_epoch = steps_per_epoch,
          epochs=total_epochs, 
          initial_epoch = num_epochs,
          validation_data=val_data.repeat(), 
          validation_steps=val_steps)

微调 30 个 epoch 后,模型的验证准确率达到了 0.986。根据准确率和损失的图,模型性能会随着 epoch 的增加而增加。

微调 30 个 epoch 后的准确率和损失。

总结

本文研究了 TensorFlow 2.0 对可用性、简洁性和灵活性的关注,并介绍了新特性是如何 TensorFlow 的学习和使用变得不那么困难的;Eager Execution 和改进的高级 API 抽象化了 TensorFlow 一直以来的复杂性,这些变化使快速实现和运行典型的图像分类实验变得简单。

在撰写本文时,只发布了 TensorFlow 2.0 的 Alpha 内测版,最终版可能要在今年的晚些时候才会发布。显然,TensorFlow 团队正在开发更直观的 TensorFlow。这可能会大范围提高机器学习工程师的生产力,因为在保留底层静态计算图的特征和灵活性的同时,还大大降低了开发的复杂程度。此外,尽管在机器学习实验中 TensorFlow 已经是热门选项了,但对初学者而言更平滑的学习曲线也是更具吸引力的选择。

请在评论中告诉我你对 TensorFlow 2.0 的看法。另外,如果需要本教程的完整代码,请参阅:

  • https://github.com/cameroncruz/notebooks/blob/master/Easy_Image_Classification_with_TF_2.ipynb

原文地址:https://towardsdatascience.com/easy-image-classification-with-tensorflow-2-0-f734fee52d13

工程深度学习框架Tensorflow 2.0 AlphaTensorFlow
81
相关数据
权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

学习曲线技术

在机器学习领域,学习曲线通常是表现学习准确率随着训练次数/时长/数据量的增长而变化的曲线

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

验证集技术

验证数据集是用于调整分类器超参数(即模型结构)的一组数据集,它有时也被称为开发集(dev set)。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

迁移学习技术

迁移学习是一种机器学习方法,就是把为任务 A 开发的模型作为初始点,重新使用在为任务 B 开发模型的过程中。迁移学习是通过从已学习的相关任务中转移知识来改进学习的新任务,虽然大多数机器学习算法都是为了解决单个任务而设计的,但是促进迁移学习的算法的开发是机器学习社区持续关注的话题。 迁移学习对人类来说很常见,例如,我们可能会发现学习识别苹果可能有助于识别梨,或者学习弹奏电子琴可能有助于学习钢琴。

特征检测技术

特征检测是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征检测的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。

图像分类技术

图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。

优化器技术

优化器基类提供了计算梯度loss的方法,并可以将梯度应用于变量。优化器里包含了实现了经典的优化算法,如梯度下降和Adagrad。 优化器是提供了一个可以使用各种优化算法的接口,可以让用户直接调用一些经典的优化算法,如梯度下降法等等。优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。用户基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer(tensorflow下的优化器包)等等这些算法。

本体技术

在计算机科学和信息科学中,本体包括表示、正式命名和定义概念,数据,实体之间的类别,属性和关系,并在一个,多个或所有域实例中。

推荐文章
/:strong