想要真的了解深度学习,除了看视频,拿数据和算力真枪实弹的练手可能比各种理论知识更重要。
编程基础不好?不会配置环境?本地GPU太贵配置太低?训练速度达不到要求?这些可能都是阻碍你搭建第一个神经网络的原因。
谷歌开发者博客的Codelabs项目上面给出了一份教程(课程链接在文末),不只是教你搭建神经网络,还给出四个实验案例,手把手教你如何使用keras、TPU、Colab。
这个练手指南被成为“仅会一点点python也能看懂”,也就是说,基础再薄弱都可以直接了解哦。
(连python都不会的同学,文摘菌前几天发布了一个100python计划,可以先行学习了再来跟着这篇文章搭建神经网络。)
四次实验均在谷歌的Collab上运行,由浅入深、循序渐进。无需进行任何设置,可以用Chromebook打开,实验环境都帮你搭建好了。
跟着文摘菌一起,是时候搭建一个属于自己的神经网络了!
快速开启!
四次实验均选择TPU支持,这会使代码运行速度大大加快,毕竟用了硬件加速。
先教会你如何在Tensorflow框架下快速加载数据,然后介绍一些tf.data.Dataset的基础知识,包括eager模式以及元组数据集等。
第二部分,手把手教你实现迁移学习,把别人训练好的模型拿过来直接使用,不用一步一步搭建也能使用强大的神经网络。除了迁移学习,在这部分还会简单介绍一些必要的知识点,包括神经元、激活函数等。
第三部分,进入卷积神经网络部分,在了解卷积层、池化层、Dense层卷积网络三个必要的组件之后,你将学会使用Keras Sequential模型构建卷积图像分类器,并使用良好的卷积层选择来微调模型。
第四部分,进入到更加前沿的部分,在接受了前面三个部分的洗礼之后,在这部分你会实现在Keras中利用TPU组建现代卷积网络和实现分类。
和在Jupyter Notebook操作方式一样,同时按住键盘的Shift和enter按钮,便可以运行代码。
如果你是首次执行,需要登录Google帐户进行身份验证。注意页面提醒就可以啦~
此notebook支持目录功能,点击网页左侧的黑色箭头可以查看。
利用Colab上的TPU训练Keras模型需要输入以下代码☟
代码语言:javascript复制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从内存加载数据。当每个乘法被执行后,其结果将被传递到下一个乘法器,同时执行加法。因此结果将是所有数据和参数乘积的和。在大量计算和数据传递的整个过程中,不需要执行任何的内存访问。
介绍完基本的操作,接下来,文摘菌带大家看看官方给出的四个实验。
Tensorflow入门:tfrecords和tf.data
此实验涉及两个tf的基础操作,一个是使用tf.data.Dataset API导入训练数据,另一个是使用TFRecord格式从GCS有效导入训练数据。
此次实验使用花卉图片的数据集,学习的目标是将其分为5种类别。使用tf.data.Dataset API 执行数据加载。
Keras和Tensorflow在其所有训练和评估功能中接受数据集。在数据集中加载数据后,API会提供对神经网络训练数据有用的所有常用功能:
代码语言:javascript复制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.jpggs://flowers-public/daisy/8094774544_35465c1c64.jpggs://flowers-public/sunflowers/9309473873_9d62b9082e.jpggs://flowers-public/dandelion/19551343954_83bb52f310_m.jpggs://flowers-public/dandelion/14199664556_188b37e51e.jpggs://flowers-public/tulips/4290566894_c7f061583d_m.jpggs://flowers-public/roses/3065719996_c16ecd5551.jpggs://flowers-public/dandelion/8168031302_6e36f39d87.jpggs://flowers-public/sunflowers/9564240106_0577e919da_n.jpggs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
tf.data.Dataset基础知识
数据通常包含多个文件,此处为图像,通过调用以下方法创建文件名数据集:
代码语言:javascript复制filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
然后,将函数“映射”到每个文件名,这些文件通常导入文件并解码为内存中的实际数据:
代码语言:javascript复制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中利用迁移学习
本次实验在keras中实现迁移学习,将强大的预训练模型应用于我们的数据集,不用费力重新训练模型。此外,本实验包含有关神经网络的必要理论解释。
神经网络分类器是由几个层的神经元组成。对于图像分类,这些可以是Dense层,或者更常见的是卷积层。它们通常通过relu激活函数激活。最后一层使用与类相同数量的神经元,并使用softmax激活。对于分类,交叉熵是最常用的损失函数,将独热编码标签(即正确答案)与神经网络预测的概率进行比较。例如,为了最大限度地减少损失,最好选择具有动量的优化器AdamOptimizer并批量训练图像和标签。
对于构建为层序列的模型,Keras提供了Sequential API。例如,使用三个Dense层的图像分类器可以在Keras中编写为:
代码语言:javascript复制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图层的预训练模型,以便你可以添加自己的模型:
代码语言:javascript复制
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中利用TPU组建卷积神经网络
本次实验,完成三个目标:
- 使用Keras Sequential模型构建卷积图像分类器。
- 在TPU上训练Keras模型
- 使用良好的卷积层选择来微调模型。
卷积将神经网络将一系列滤波器应用于图像的原始像素数据以提取和学习更高级别的特征,使得该模型能够将这些特征用于分类。卷积将神经网络包含三个组件:
- 卷积层,将特定数量的卷积滤镜(convolution filters)应用于图像。对于每个子区域,图层执行一组数学运算以在输出特征映射中生成单个值。
- 池化层(Pooling layers),负责对由卷积层提取的图像数据进行下采样以减少特征映射的维度以提高处理效率。常用的池化算法是最大池化,其提取特征地图的子区域(例如,2×2像素的块),保持它们的最大值并丢弃所有其他值。
- Dense层,对由卷积图层提取的特征并由共用图层进行下采样执行分类。Dense层是全连接的神经网络,在Dense层中,图层中的每个节点都连接到前一图层中的每个节点。
用最大池化做卷积的动画示例如下☟
用Softmax激活函数连接分类器,典型的卷积分类器如下☟
在keras中搭建神经网络代码如下:
代码语言:javascript复制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
在Keras中利用TPU组建现代卷积网络和实现分类
之前三个实验已经分别介绍了TPU、迁移学习和卷积网络,是不是已经觉得很厉害了?别着急,最后的大招来了,本次实验我们将实现在Keras中利用TPU组建现代卷积网络和实现分类。
现代卷积架构(Modern convolutions networks)
简而言之,从"Inception" 和 "Inception v2"开始的现代卷积网络通常使用“模块”,其中在同一输入上同时尝试不同的卷积层,它们的输出被连接并且网络通过训练决定哪个层是最有用的。
在Keras中,要创建数据流可以分支进出的模型,必须使用“functional”模型。这是一个例子:
代码语言:javascript复制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