新智元推荐
来源:大数据文摘(ID:BigDataDigest)
编译:曹培信、周素云、蒋宝尚
想要真的了解深度学习,除了看视频,拿数据和算力真枪实弹的练手可能比各种理论知识更重要。
编程基础不好?不会配置环境?本地 GPU 太贵配置太低?训练速度达不到要求?这些可能都是阻碍你搭建第一个神经网络的原因。
谷歌开发者博客的 Codelabs 项目上面给出了一份教程(课程链接在文末),不只是教你搭建神经网络,还给出四个实验案例,手把手教你如何使用 keras、TPU、Colab。
这个练手指南被成为 “仅会一点点 python 也能看懂”,也就是说,基础再薄弱都可以直接了解哦。
四次实验均在谷歌的 Collab 上运行,由浅入深、循序渐进。无需进行任何设置,可以用 Chromebook 打开,实验环境都帮你搭建好了。
是时候搭建一个属于自己的神经网络了!
四次实验均选择 TPU 支持,这会使代码运行速度大大加快,毕竟用了硬件加速。
先教会你如何在 Tensorflow 框架下快速加载数据,然后介绍一些 tf.data.Dataset 的基础知识,包括 eager 模式以及元组数据集等。
第二部分,手把手教你实现迁移学习,把别人训练好的模型拿过来直接使用,不用一步一步搭建也能使用强大的神经网络。除了迁移学习,在这部分还会简单介绍一些必要的知识点,包括神经元、激活函数等。
第三部分,进入卷积神经网络部分,在了解卷积层、池化层、Dense 层卷积网络三个必要的组件之后,你将学会使用 Keras Sequential 模型构建卷积图像分类器,并使用良好的卷积层选择来微调模型。
第四部分,进入到更加前沿的部分,在接受了前面三个部分的洗礼之后,在这部分你会实现在 Keras 中利用 TPU 组建现代卷积网络和实现分类。
和在 Jupyter Notebook 操作方式一样,同时按住键盘的 Shift 和 enter 按钮,便可以运行代码。
如果你是首次执行,需要登录 Google 帐户进行身份验证。注意页面提醒就可以啦~
此 notebook 支持目录功能,点击网页左侧的黑色箭头可以查看。
利用 Colab 上的 TPU 训练 Keras 模型需要输入以下代码☟
tpu = tf.contrib.cluster_resolver.TPUClusterResolver(TPU_ADDRESS)
strategy = tf.contrib.tpu.TPUDistributionStrategy(tpu)
tpu_model = tf.contrib.tpu.keras_to_tpu_model(model, strategy=strategy)
tpu_model.fit(get_training_dataset,
steps_per_epoch=TRAIN_STEPS, epochs=EPOCHS,
validation_data=get_validation_dataset, validation_steps=VALID_STEPS)
本质上是在 keras 中调用 keras_to_tpu_model,部署额外的硬件可以通过增加训练批次的大小增加训练过程。需要注意的是目前,Keras 支持仅限于 8 个核心或一个 Cloud TPU。
注:TPU 可以在神经网络运算上达到高计算吞吐量,同时能耗和物理空间都很小。因为 TPU 从内存加载数据。当每个乘法被执行后,其结果将被传递到下一个乘法器,同时执行加法。因此结果将是所有数据和参数乘积的和。在大量计算和数据传递的整个过程中,不需要执行任何的内存访问。
介绍完基本的操作,接下来,看看官方给出的四个实验。
此实验涉及两个 tf 的基础操作,一个是使用 tf.data.Dataset API 导入训练数据,另一个是使用 TFRecord 格式从 GCS 有效导入训练数据。
此次实验使用花卉图片的数据集,学习的目标是将其分为 5 种类别。使用 tf.data.Dataset API 执行数据加载。
Keras 和 Tensorflow 在其所有训练和评估功能中接受数据集。在数据集中加载数据后,API 会提供对神经网络训练数据有用的所有常用功能:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
dataset = dataset.prefetch(-1) # prefetch next batch(es) while training
了解 API 并试着运行:
https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/02_Dataset_playground.ipynb
关于鲜花数据集,数据集按 5 个文件夹组织,每个文件夹都包含一种花。文件夹名为向日葵,雏菊,蒲公英,郁金香和玫瑰。数据托管在 Google 云端存储上的公共存储区中。
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
tf.data.Dataset 基础知识
数据通常包含多个文件,此处为图像,通过调用以下方法创建文件名数据集:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
然后,将函数 “映射” 到每个文件名,这些文件通常导入文件并解码为内存中的实际数据:
def decode_jpeg(filename):
bits = tf.read_file(filename)
image = tf.image.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
有关 tf.data.Dataset 的基础知识、tf.data.Dataset 和 eager 模式、元组数据集的详细步骤,请戳:
https://codelabs.developers.google.com/codelabs/keras-flowers-data/#3
但逐个加载图像很慢,在迭代此数据集时,每秒只可以加载 1-2 个图像。我们将用训练的硬件加速器,可以将速率提高很多倍。
快速加载数据
我们将在本实验中使用的 Tensor Processing Unit(TPU)硬件加速器。Google 云端存储(GCS)能够保持极高的吞吐量,但与所有云存储系统一样,形成连接时需要来回请求。因此,将数据存储为数千个单独的文件并不理想。我们将在少量文件中批量处理它们,并使用 tf.data.Dataset 的强大功能一次性读取多个文件。
通过加载图像文件的代码将它们调整为通用大小,然后将它们存储在 16 个 TFRecord 文件中,代码链接如下:
https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/03_Flower_pictures_to_TFRecords.ipynb
经验法则是将数据分成几个(10s 到 100s)的大文件(10s 到 100s 的 MB)。如果有太多文件,例如数千个文件,那么访问每个文件的时间可能会开始妨碍。如果文件太少,例如一两个文件,那么就无法并行获取多个文件的优势。
TFRecord 文件格式
Tensorflow 用于存储数据的首选文件格式是基于 protobuf 的 TFRecord 格式。其他序列化格式也可以使用,可以通过以下方式直接从 TFRecord 文件加载数据集:
filenames_dataset = tf.data.Dataset.list_files(FILENAME_PATTERN)
tfrecords_dataset = tf.data.TFRecordDataset(filenames,num_parallel_reads = 32)
但你拥有 TFRecords 的数据集时,下一步解码步骤就是从每个记录中获得数据。如前所述,你将使用 Dataset.map,并注意 num_parallel_reads=32 参数。这将从 32 个 TFRecord 文件并行加载数据,可以获得最佳性能。
本次实验在 keras 中实现迁移学习,将强大的预训练模型应用于我们的数据集,不用费力重新训练模型。此外,本实验包含有关神经网络的必要理论解释。
神经网络分类器是由几个层的神经元组成。对于图像分类,这些可以是 Dense 层,或者更常见的是卷积层。它们通常通过 relu 激活函数激活。最后一层使用与类相同数量的神经元,并使用 softmax 激活。对于分类,交叉熵是最常用的损失函数,将独热编码标签(即正确答案)与神经网络预测的概率进行比较。例如,为了最大限度地减少损失,最好选择具有动量的优化器 AdamOptimizer 并批量训练图像和标签。
对于构建为层序列的模型,Keras 提供了 Sequential API。例如,使用三个 Dense 层的图像分类器可以在 Keras 中编写为:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
tf.keras.layers.Dense(500, activation="relu"),
tf.keras.layers.Dense(50, activation="relu"),
tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
Dense 神经网络
这是用于分类图像的最简单的神经网络。它由分层排列的 “神经元” 组成。第一层处理输入数据并将其输出馈送到其他层。之所以被称为 “Dense” 是因为每个神经元都连接到前一层中的所有神经元。
你可以将图像的所有像素的 RGB 值展开为长矢量并将其用作输入,从而将图像输入到此类网络中。它不是图像识别的最佳技术,但我们稍后会对其进行改进。
神经元
“神经元” 计算其所有输入的并进行加权求和,添加一个称为 “偏差” 的值,并通过所谓的 “激活函数” 提供结果。权重和偏差最初是未知的。它们将被随机初始化并通过在许多已知数据上训练神经网络来 “学习”。
最流行的激活函数被称为 RELU(Rectified Linear Unit)如上图所示。
Softmax 激活
我们将花分为 5 类(玫瑰,郁金香,蒲公英,雏菊,向日葵),使用经典 RELU 激活函数。然而,在最后一层,我们想要计算 0 到 1 之间的数字,表示这朵花是玫瑰,郁金香等的概率。为此,我们将使用名为 “softmax” 的激活函数。
在矢量上应用 softmax 函数是通过取每个元素的指数然后归一化矢量来完成的,通常使用 L1 范数(绝对值之和),使得这些值加起来可以解释为概率。
对于图像分类问题,Dense 层可能是不够的。但我们也可以另辟蹊径!有完整的卷积神经网络可供下载。我们可以切掉它们的最后一层 softmax 分类,并用下载的替换它。所有训练过的权重和偏差保持不变,你只需重新训练你添加的 softmax 层。这种技术被称为迁移学习,只要预先训练神经网络的数据集与你的 “足够接近”,它就可以工作。
请打开下面的 notebook,同时按住 Shift-ENTER 运行代码:
https://codelabs.developers.google.com/codelabs/keras-flowers-convnets/#0
插图:使用已经训练过的复杂卷积神经网络作为黑匣子,仅对分类的最后一层进行再训练。这是迁移学习。
通过迁移学习,你可以从顶级研究人员已经开发的高级卷积神经网络架构和大量图像数据集的预训练中受益。在我们的案例中,我们将从 ImageNet 训练的网络迁移学习。
在 Keras 中,可以从 tf.keras.applications.* 集合中实例化预先训练的模型。例如,MobileNet V2 是一个非常好的卷积架构,其尺寸合理。通过选择 include_top=False,你可以获得没有最终 softmax 图层的预训练模型,以便你可以添加自己的模型:
pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(5, activation='softmax')
])
另请注意 pretrained_model.trainable = False 设置。它冻结了预训练模型的权重和偏差,因此你只能训练 softmax 图层。这通常针对相对较少的权重并且可以快速完成而无需非常大的数据集。但是,如果你确实拥有大量数据,那么 pretrained_model.trainable = True 可以让迁移学习更好地工作。然后,经过预先训练的权重可提供出色的初始值,并且仍可通过训练进行调整,以更好地适应你的问题。
最后,请注意在 dense softmax 层前插入 Flatten()层。Dense 层对数据的平面向量起作用,但我们不知道这是否是预训练模型返回的内容,这就是我们需要扁平化的原因。在下一章中,当我们深入研究卷积体系结构时,我们将解释卷积层返回的数据格式。
本次实验,完成三个目标:
使用 Keras Sequential 模型构建卷积图像分类器。
在 TPU 上训练 Keras 模型
使用良好的卷积层选择来微调模型。
卷积将神经网络将一系列滤波器应用于图像的原始像素数据以提取和学习更高级别的特征,使得该模型能够将这些特征用于分类。卷积将神经网络包含三个组件:
卷积层,将特定数量的卷积滤镜(convolution filters)应用于图像。对于每个子区域,图层执行一组数学运算以在输出特征映射中生成单个值。
池化层(Pooling layers),负责对由卷积层提取的图像数据进行下采样以减少特征映射的维度以提高处理效率。常用的池化算法是最大池化,其提取特征地图的子区域(例如,2×2 像素的块),保持它们的最大值并丢弃所有其他值。
Dense 层,对由卷积图层提取的特征并由共用图层进行下采样执行分类。Dense 层是全连接的神经网络,在 Dense 层中,图层中的每个节点都连接到前一图层中的每个节点。
用最大池化做卷积的动画示例如下☟
用 Softmax 激活函数连接分类器,典型的卷积分类器如下☟
在 keras 中搭建神经网络代码如下:
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
在搭建的过程中,必须在权重和偏差之间找到适当的平衡点,如果权重太大,神经网络可能无法代表复杂性,如果参数太多,可能导致过拟合。所以在在 Keras 中,用 model.summary () 函数显示模型的结构和参数:
具体代码地址:
https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/07_Keras_Flowers_TPU_playground.ipynb
之前三个实验已经分别介绍了 TPU、迁移学习和卷积网络,是不是已经觉得很厉害了?别着急,最后的大招来了,本次实验我们将实现在 Keras 中利用 TPU 组建现代卷积网络和实现分类。
现代卷积架构(Modern convolutions networks)
简而言之,从 "Inception" 和 "Inception v2" 开始的现代卷积网络通常使用 “模块”,其中在同一输入上同时尝试不同的卷积层,它们的输出被连接并且网络通过训练决定哪个层是最有用的。
在 Keras 中,要创建数据流可以分支进出的模型,必须使用 “functional” 模型。这是一个例子:
l = tf.keras.layers # syntax shortcut
y = l.Conv2D(filters=32, kernel_size=3, padding='same',
activation='relu', input_shape=[192, 192, 3])(x) # x=input image
# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation
# many more layers ...
# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)
其他小技巧
小型 3x3 滤波器
在此图中,你可以看到两个连续 3x3 滤波器的结果。尝试追溯哪些数据点对结果有贡献:这两个连续的 3x3 滤波器计算 5x5 区域的某种组合。它与 5x5 滤波器计算的组合并不完全相同,但值得尝试,因为两个连续的 3x3 滤波器比单个 5x5 滤波器效率更高。
1x1 卷积?
在数学术语中,“1x1” 卷积是常数的乘法,而不是非常有用的概念。但是,在卷积神经网络中,请记住滤波器应用于数据立方体,而不仅仅是 2D 图像。因此,“1x1” 滤波器计算 1x1 数据列的加权和(参见图示),当你在数据中滑动时,你将获得输入通道的线性组合。这实际上很有用。如果你将通道视为单个过滤操作的结果,例如 “猫耳朵” 的过滤器,另一个用于 “猫胡须”,第三个用于 “猫眼睛”,则 “1x1” 卷积层将计算多个这些特征的可能线性组合,在寻找 “猫” 时可能很有用。
Squeezenet
将这些想法融合在一起的简单方法已在 “Squeezenet” 论文中展示,即一种仅使用 1x1 和 3x3 卷积层的卷积模块设计。
https://arxiv.org/abs/1602.07360
基于 “fire model” 的 squeezenet 架构。它们交替使用 1x1 层,在垂直维度上 “挤压” 输入数据,然后是两个并行的 1x1 和 3x3 卷积层,再次 “扩展” 数据深度。
构建一个受 squeezenet 启发的卷积神经网络时,我们就不能直接像上面一样直接堆叠已有模块,需要将模型代码更改为 Keras 的 “功能样式”,来定义自己的模块。
想要尝试 Squeezenet 架构练习的戳以下链接:
https://codelabs.developers.google.com/codelabs/keras-flowers-squeezenet/#6
最后,手把手教程运行代码如下:
https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/07_Keras_Flowers_TPU_playground.ipynb
最后,再次给出四个实验的链接,供参考哟~
https://codelabs.developers.google.com/codelabs/keras-flowers-data/#2
https://codelabs.developers.google.com/codelabs/keras-flowers-transfer-learning/#2
https://codelabs.developers.google.com/codelabs/keras-flowers-convnets/#0
https://codelabs.developers.google.com/codelabs/keras-flowers-squeezenet/#0
此项目支持答疑,打开下列网址提交你的问题
https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/07_Keras_Flowers_TPU_squeezenet.ipynb
本文经授权转载自大数据文摘(ID:BigDataDigest)
新智元春季招聘开启,一起弄潮 AI 之巅!
岗位详情请戳:
【加入社群】
新智元 AI 技术 + 产业社群招募中,欢迎对 AI 技术 + 产业落地感兴趣的同学,加小助手微信号:aiera2015_2 入群;通过审核后我们将邀请进群,加入社群后务必修改群备注(姓名 - 公司 - 职位;专业群审核较严,敬请谅解)。