TensorFlow 1.x 深度学习秘籍:1~5(1)https://developer.aliyun.com/article/new/ai#ZqvnG
五、高级卷积神经网络
在本章中,我们将讨论如何将卷积神经网络(CNN)用于除图像以外的领域中的深度学习。 我们的注意力将首先集中在文本分析和自然语言处理(NLP)上。 在本章中,我们将介绍一些用于以下方面的方法:
- 创建卷积网络进行情感分析
- 检查 VGG 预建网络学习了哪些过滤器
- 使用 VGGNet,ResNet,Inception 和 Xception 对图像进行分类
- 复用预先构建的深度学习模型来提取特征
- 用于迁移学习的非常深的 Inception-v3 网络
- 使用膨胀的 ConvNets,WaveNet 和 NSynth 生成音乐
- 回答有关图像的问题(可视化问答)
- 使用预训练网络通过六种不同方式来分类视频
介绍
在上一章中,我们了解了如何将 ConvNets 应用于图像。 在本章中,我们将类似的思想应用于文本。
文本和图像有什么共同点? 乍一看,很少。 但是,如果我们将句子或文档表示为矩阵,则此矩阵与每个单元都是像素的图像矩阵没有区别。 因此,下一个问题是,我们如何将文本表示为矩阵? 好吧,这很简单:矩阵的每一行都是一个向量,代表文本的基本单位。 当然,现在我们需要定义什么是基本单位。 一个简单的选择就是说基本单位是一个字符。 另一个选择是说基本单位是一个单词,另一个选择是将相似的单词聚合在一起,然后用代表符号表示每个聚合(有时称为簇或嵌入)。
请注意,无论我们的基本单位采用哪种具体选择,我们都需要从基本单位到整数 ID 的 1:1 映射,以便可以将文本视为矩阵。 例如,如果我们有一个包含 10 行文本的文档,并且每行都是 100 维嵌入,那么我们将用10 x 100
的矩阵表示文本。 在这个非常特殊的图像中,如果该句子x
包含位置y
表示的嵌入,则打开像素。 您可能还会注意到,文本实际上不是矩阵,而是向量,因为位于文本相邻行中的两个单词几乎没有共同点。 确实,与图像的主要区别在于,相邻列中的两个像素最有可能具有某种相关性。
现在您可能会想:我知道您将文本表示为向量,但是这样做会使我们失去单词的位置,而这个位置应该很重要,不是吗?
好吧,事实证明,在许多实际应用中,知道一个句子是否包含特定的基本单位(一个字符,一个单词或一个合计)是非常准确的信息,即使我们不记住句子中的确切位置也是如此。 基本单元位于。
创建用于情感分析的卷积网络
在本秘籍中,我们将使用 TFLearn 创建基于 CNN 的情感分析深度学习网络。 如上一节所述,我们的 CNN 将是一维的。 我们将使用 IMDb 数据集,用于训练的 45,000 个高度受欢迎的电影评论和用于测试的 5,000 个集合。
准备
TFLearn 具有用于自动从网络下载数据集并促进卷积网络创建的库,因此让我们直接看一下代码。
操作步骤
我们按以下步骤进行:
- 导入 TensorFlow
tflearn
和构建网络所需的模块。 然后,导入 IMDb 库并执行一键编码和填充:
import tensorflow as tf import tflearn from tflearn.layers.core import input_data, dropout, fully_connected from tflearn.layers.conv import conv_1d, global_max_pool from tflearn.layers.merge_ops import merge from tflearn.layers.estimator import regression from tflearn.data_utils import to_categorical, pad_sequences from tflearn.datasets import imdb
- 加载数据集,将句子填充到最大长度为 0 的位置,并对标签执行两个编码,分别对应于真值和假值的两个值。 注意,参数
n_words
是要保留在词汇表中的单词数。 所有多余的单词都设置为未知。 另外,请注意trainX
和trainY
是稀疏向量,因为每个评论很可能包含整个单词集的子集:
# IMDb Dataset loading train, test, _ = imdb.load_data(path='imdb.pkl', n_words=10000, valid_portion=0.1) trainX, trainY = train testX, testY = test #pad the sequence trainX = pad_sequences(trainX, maxlen=100, value=0.) testX = pad_sequences(testX, maxlen=100, value=0.) #one-hot encoding trainY = to_categorical(trainY, nb_classes=2) testY = to_categorical(testY, nb_classes=2)
- 打印一些维度以检查刚刚处理的数据并了解问题的维度是什么:
print ("size trainX", trainX.size) print ("size testX", testX.size) print ("size testY:", testY.size) print ("size trainY", trainY.size) size trainX 2250000 size testX 250000 size testY: 5000 site trainY 45000
- 为数据集中包含的文本构建嵌入。 就目前而言,将此步骤视为一个黑盒子,该黑盒子接受这些单词并将它们映射到聚合(群集)中,以便相似的单词可能出现在同一群集中。 请注意,先前步骤的词汇是离散且稀疏的。 通过嵌入,我们将创建一个映射,该映射会将每个单词嵌入到连续的密集向量空间中。 使用此向量空间表示将为我们提供词汇表的连续,分布式表示。 当我们谈论 RNN 时,将详细讨论如何构建嵌入:
# Build an embedding network = input_data(shape=[None, 100], name='input') network = tflearn.embedding(network, input_dim=10000, output_dim=128)
- 建立一个合适的
convnet
。 我们有三个卷积层。 由于我们正在处理文本,因此我们将使用一维卷积网络,并且各层将并行运行。 每层采用大小为 128 的张量(嵌入的输出),并应用有效填充,激活函数 ReLU 和 L2regularizer
的多个滤波器(分别为 3、4、5)。 然后,将每个层的输出与合并操作连接在一起。 此后,添加一个最大池层,然后以 50% 的概率进行删除。 最后一层是具有 softmax 激活的完全连接层:
#Build the convnet branch1 = conv_1d(network, 128, 3, padding='valid', activation='relu', regularizer="L2") branch2 = conv_1d(network, 128, 4, padding='valid', activation='relu', regularizer="L2") branch3 = conv_1d(network, 128, 5, padding='valid', activation='relu', regularizer="L2") network = merge([branch1, branch2, branch3], mode='concat', axis=1) network = tf.expand_dims(network, 2) network = global_max_pool(network) network = dropout(network, 0.5) network = fully_connected(network, 2, activation='softmax')
- 学习阶段意味着使用
categorical_crossentropy
作为损失函数的 Adam 优化器:
network = regression(network, optimizer='adam', learning_rate=0.001, loss='categorical_crossentropy', name='target')
- 然后,我们使用
batch_size = 32
运行训练,并观察训练和验证集达到的准确率。 如您所见,在预测电影评论所表达的情感方面,我们能够获得 79% 的准确率:
# Training model = tflearn.DNN(network, tensorboard_verbose=0) model.fit(trainX, trainY, n_epoch = 5, shuffle=True, validation_set=(testX, testY), show_metric=True, batch_size=32) Training Step: 3519 | total loss: 0.09738 | time: 85.043s | Adam | epoch: 005 | loss: 0.09738 - acc: 0.9747 -- iter: 22496/22500 Training Step: 3520 | total loss: 0.09733 | time: 86.652s | Adam | epoch: 005 | loss: 0.09733 - acc: 0.9741 | val_loss: 0.58740 - val_acc: 0.7944 -- iter: 22500/22500 --
工作原理
用于句子分类的卷积神经网络,Yoon Kim,EMNLP 2014。 请注意,由于筛选器窗口对连续单词进行操作,因此本文提出的模型保留了一些有关位置的信息。 从论文中提取的以下图像以图形方式表示了网络之外的主要直觉。 最初,文本被表示为基于标准嵌入的向量,从而为我们提供了一维密集空间中的紧凑表示。 然后,使用多个标准一维卷积层处理矩阵。
请注意,模型使用多个过滤器(窗口大小不同)来获取多个特征。 之后,进行最大池操作,其思想是捕获最重要的特征-每个特征图的最大值。 为了进行正则化,该文章建议在倒数第二层上采用对权重向量的 L2 范数有约束的丢弃项。 最后一层将输出情感为正或负。
为了更好地理解该模型,有以下几点观察:
- 过滤器通常在连续空间上卷积。 对于图像,此空间是像素矩阵表示形式,在高度和宽度上在空间上是连续的。 对于文本而言,连续空间无非是连续单词自然产生的连续尺寸。 如果仅使用单次编码表示的单词,则空间稀疏;如果使用嵌入,则由于聚集了相似的单词,因此生成的空间密集。
- 图像通常具有三个通道(RGB),而文本自然只有一个通道,因为我们无需表示颜色。
更多
论文《用于句子分类的卷积神经网络》(Yoon Kim,EMNLP 2014)进行了广泛的实验。 尽管对超参数的调整很少,但具有一层卷积的简单 CNN 在句子分类方面的表现却非常出色。 该论文表明,采用一组静态嵌入(将在我们谈论 RNN 时进行讨论),并在其之上构建一个非常简单的卷积网络,实际上可以显着提高情感分析的表现:
使用 CNN 进行文本分析是一个活跃的研究领域。 我建议看看以下文章:
- 《从头开始理解文本》(张翔,Yann LeCun)。 本文演示了我们可以使用 CNN 将深度学习应用于从字符级输入到抽象文本概念的文本理解。 作者将 CNN 应用于各种大规模数据集,包括本体分类,情感分析和文本分类,并表明它们可以在不了解单词,词组,句子或任何其他句法或语义结构的情况下实现惊人的表现。 一种人类的语言。 这些模型适用于英文和中文。
检查 VGG 预建网络了解了哪些过滤器
在本秘籍中,我们将使用 keras-vis,这是一个外部 Keras 包,用于直观检查预建的 VGG16 网络从中学到了什么不同的过滤器。 这个想法是选择一个特定的 ImageNet 类别,并了解 VGG16 网络如何学会代表它。
准备
第一步是选择用于在 ImageNet 上训练 VGG16 的特定类别。 假设我们采用类别 20,它对应于下图中显示的美国北斗星鸟:
可以在网上找到 ImageNet 映射作为 python 泡菜字典,其中 ImageNet 1000 类 ID 映射到了人类可读的标签。
操作步骤
我们按以下步骤进行:
- 导入 matplotlib 和 keras-vis 使用的模块。 此外,还导入预构建的 VGG16 模块。 Keras 使处理此预建网络变得容易:
from matplotlib import pyplot as plt from vis.utils import utils from vis.utils.vggnet import VGG16 from vis.visualization import visualize_class_activation
- 通过使用 Keras 中包含的并经过 ImageNet 权重训练的预构建层来访问 VGG16 网络:
# Build the VGG16 network with ImageNet weights model = VGG16(weights='imagenet', include_top=True) model.summary() print('Model loaded.')
- 这就是 VGG16 网络在内部的外观。 我们有许多卷积网络,与 2D 最大池化交替使用。 然后,我们有一个展开层,然后是三个密集层。 最后一个称为预测,并且这一层应该能够检测到高级特征,例如人脸或我们的鸟类形状。 请注意,顶层已明确包含在我们的网络中,因为我们想可视化它学到的知识:
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_2 (InputLayer) (None, 224, 224, 3) 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 _________________________________________________________________ flatten (Flatten) (None, 25088) 0 _________________________________________________________________ fc1 (Dense) (None, 4096) 102764544 _________________________________________________________________ fc2 (Dense) (None, 4096) 16781312 _________________________________________________________________ predictions (Dense) (None, 1000) 4097000 ================================================================= Total params: 138,357,544 Trainable params: 138,357,544 Non-trainable params: 0 _________________________________________________________________ Model loaded.
从外观上看,网络可以如下图所示:
VGG16 网络
- 现在,让我们着重于通过关注 American Dipper(ID 20)来检查最后一个预测层的内部外观:
layer_name = 'predictions' layer_idx = [idx for idx, layer in enumerate(model.layers) if layer.name == layer_name][0] # Generate three different images of the same output index. vis_images = [] for idx in [20, 20, 20]: img = visualize_class_activation(model, layer_idx, filter_indices=idx, max_iter=500) img = utils.draw_text(img, str(idx)) vis_images.append(img)
- 让我们在给定特征的情况下显示特定层的生成图像,并观察网络如何在内部看到美国北斗星鸟的概念:
因此,这就是神经网络在内部代表鸟类的方式。 这是一种令人毛骨悚然的形象,但我发誓没有为网络本身提供任何特定种类的人造药物! 这正是这种特殊的人工网络自然学到的东西。
- 您是否仍然想了解更多? 好吧,让我们选择一个较早的层,并代表网络如何在内部看到相同的
American Dipper
训练类别:
layer_name = 'block3_conv1' layer_idx = [idx for idx, layer in enumerate(model.layers) if layer.name == layer_name][0] vis_images = [] for idx in [20, 20, 20]: img = visualize_class_activation(model, layer_idx, filter_indices=idx, max_iter=500) img = utils.draw_text(img, str(idx)) vis_images.append(img) stitched = utils.stitch_images(vis_images) plt.axis('off') plt.imshow(stitched) plt.title(layer_name) plt.show()
以下是上述代码的输出:
不出所料,该特定层正在学习非常基本的特征,例如曲线。 但是,卷积网络的真正力量在于,随着我们对模型的深入研究,网络会推断出越来越复杂的特征。
工作原理
密集层的 keras-vis 可视化的关键思想是生成一个输入图像,该图像最大化与鸟类类相对应的最终密集层输出。 因此,实际上该模块的作用是解决问题。 给定具有权重的特定训练密集层,将生成一个新的合成图像,它最适合该层本身。
每个转换滤波器都使用类似的想法。 在这种情况下,请注意,由于卷积网络层在原始像素上运行,因此可以通过简单地可视化其权重来解释它。 后续的卷积过滤器对先前的卷积过滤器的输出进行操作,因此直接可视化它们不一定很有解释性。 但是,如果我们独立地考虑每一层,我们可以专注于仅生成可最大化滤波器输出的合成输入图像。
更多
GitHub 上的 keras-vis 存储库提供了一组很好的可视化示例,这些示例说明了如何内部检查网络,包括最近的显着性映射,其目的是在图像经常包含其他元素(例如草)时检测图像的哪个部分对特定类别(例如老虎)的训练贡献最大。 种子文章是《深度卷积网络:可视化图像分类模型和显着性图》(Karen Simonyan,Andrea Vedaldi,Andrew Zisserman),并在下面报告了从 Git 存储库中提取的示例,在该示例中,网络可以自行了解定义为老虎的图像中最突出的部分是:
将 VGGNet,ResNet,Inception 和 Xception 用于图像分类
图像分类是典型的深度学习应用。 由于 ImageNet 图像数据库,该任务的兴趣有了最初的增长。 它按照 WordNet 层次结构(目前仅是名词)来组织,其中每个节点都由成百上千的图像描绘。 更准确地说,ImageNet 旨在将图像标记和分类为将近 22,000 个单独的对象类别。 在深度学习的背景下,ImageNet 通常指的是 ImageNet 大规模视觉识别挑战,或简称 ILSVRC 中包含的工作。在这种情况下,目标是训练一个模型,该模型可以将输入图像分类为 1,000 个单独的对象类别。 在此秘籍中,我们将使用超过 120 万个训练图像,50,000 个验证图像和 100,000 个测试图像的预训练模型。
VGG16 和 VGG19
在《用于大型图像识别的超深度卷积网络》(Karen Simonyan,Andrew Zisserman,2014 年)中,引入了 VGG16 和 VGG19。 该网络使用3×3
卷积层堆叠并与最大池交替,两个 4096 个全连接层,然后是 softmax 分类器。 16 和 19 代表网络中权重层的数量(列 D 和 E):
在 2015 年,拥有 16 或 19 层就足以考虑网络的深度,而今天(2017 年)我们达到了数百层。 请注意,VGG 网络的训练速度非常慢,并且由于末端的深度和完全连接的层数,它们需要较大的权重空间。
ResNet
ResNet 已在《用于图像识别的深度残差学习》(何开明,张向宇,任少青,孙健,2015)中引入。 该网络非常深,可以使用称为残差模块的标准网络组件使用标准的随机下降梯度进行训练,然后使用该网络组件组成更复杂的网络(该网络在网络中称为子网络)。
与 VGG 相比,ResNet 更深,但是模型的大小更小,因为使用了全局平均池化操作而不是全密层。
Inception
在《重新思考计算机视觉的初始架构》(Christian Szegedy,Vincent Vanhoucke,Sergey Ioffe,Jonathon Shlens,Zbigniew Wojna,2015 年)中引入了 Inception 。关键思想是在同一模块中具有多种大小的卷积作为特征提取并计算1×1
、3×3
和5×5
卷积。 这些滤波器的输出然后沿着通道尺寸堆叠,并发送到网络的下一层。 下图对此进行了描述:
在“重新思考计算机视觉的 Inception 架构”中描述了 Inception-v3,而在《Inception-v4,Inception-ResNet 和残余连接对学习的影响》(Szegedy,Sergey Ioffe,Vincent Vanhoucke,Alex Alemi,2016 年)中描述了 Inception-v4。
Xception
Xception 是 Inception 的扩展,在《Xception:具有深度可分离卷积的深度学习》(FrançoisChollet,2016 年)中引入。 Xception 使用一种称为深度可分离卷积运算的新概念,该概念使其在包含 3.5 亿张图像和 17,000 个类别的大型图像分类数据集上的表现优于 Inception-v3。 由于 Xception 架构具有与 Inception-v3 相同数量的参数,因此表现的提高并不是由于容量的增加,而是由于模型参数的更有效使用。
准备
此秘籍使用 Keras,因为该框架已预先完成了上述模块的实现。 Keras 首次使用时会自动下载每个网络的权重,并将这些权重存储在本地磁盘上。 换句话说,您不需要重新训练网络,而是可以利用互联网上已经可用的训练。 在您希望将网络分类为 1000 个预定义类别的假设下,这是正确的。 在下一个秘籍中,我们将了解如何从这 1,000 个类别开始,并通过称为迁移学习的过程将它们扩展到自定义集合。
操作步骤
我们按以下步骤进行:
- 导入处理和显示图像所需的预建模型和其他模块:
from keras.applications import ResNet50 from keras.applications import InceptionV3 from keras.applications import Xception # TensorFlow ONLY from keras.applications import VGG16 from keras.applications import VGG19 from keras.applications import imagenet_utils from keras.applications.inception_v3 import preprocess_input from keras.preprocessing.image import img_to_array from keras.preprocessing.image import load_img import numpy as np import matplotlib.pyplot as plt from matplotlib.pyplot import imshow from PIL import Image %matplotlib inline
- 定义用于记忆用于训练网络的图像大小的映射。 这些是每个模型的众所周知的常数:
MODELS = { "vgg16": (VGG16, (224, 224)), "vgg19": (VGG19, (224, 224)), "inception": (InceptionV3, (299, 299)), "xception": (Xception, (299, 299)), # TensorFlow ONLY "resnet": (ResNet50, (224, 224)) }
- 定义用于加载和转换每个图像的辅助函数。 注意,预训练网络已在张量上训练,该张量的形状还包括
batch_size
的附加维度。 因此,我们需要将此尺寸添加到图像中以实现兼容性:
def image_load_and_convert(image_path, model): pil_im = Image.open(image_path, 'r') imshow(np.asarray(pil_im)) # initialize the input image shape # and the pre-processing function (this might need to be changed inputShape = MODELS[model][1] preprocess = imagenet_utils.preprocess_input image = load_img(image_path, target_size=inputShape) image = img_to_array(image) # the original networks have been trained on an additional # dimension taking into account the batch size # we need to add this dimension for consistency # even if we have one image only image = np.expand_dims(image, axis=0) image = preprocess(image) return image
- 定义用于对图像进行分类的辅助函数,并在预测上循环,并显示 5 级预测以及概率:
def classify_image(image_path, model): img = image_load_and_convert(image_path, model) Network = MODELS[model][0] model = Network(weights="imagenet") preds = model.predict(img) P = imagenet_utils.decode_predictions(preds) # loop over the predictions and display the rank-5 predictions # along with probabilities for (i, (imagenetID, label, prob)) in enumerate(P[0]): print("{}. {}: {:.2f}%".format(i + 1, label, prob * 100))
5.然后开始测试不同类型的预训练网络:
classify_image("images/parrot.jpg", "vgg16")
接下来,您将看到具有相应概率的预测列表:
1.金刚鹦鹉:99.92%
2.美洲豹:0.03%
3.澳洲鹦鹉:0.02%
4.蜂食者:0.02%
5.巨嘴鸟:0.00%
classify_image("images/parrot.jpg", "vgg19")
1.金刚鹦鹉:99.77%
2.鹦鹉:0.07%
3.巨嘴鸟:0.06%
4.犀鸟:0.05%
5.贾卡马尔:0.01%
classify_image("images/parrot.jpg", "resnet")
1.金刚鹦鹉:97.93%
2.孔雀:0.86%
3.鹦鹉:0.23%
4. j:0.12%
5.杰伊:0.12%
classify_image("images/parrot_cropped1.jpg", "resnet")
1.金刚鹦鹉:99.98%
2.鹦鹉:0.00%
3.孔雀:0.00%
4.硫凤头鹦鹉:0.00%
5.巨嘴鸟:0.00%
classify_image("images/incredible-hulk-180.jpg", "resnet")
1. comic_book:99.76%
2. book_jacket:0.19%
3.拼图游戏:0.05%
4.菜单:0.00%
5.数据包:0.00%
classify_image("images/cropped_panda.jpg", "resnet")
大熊猫:99.04%
2.英迪尔:0.59%
3.小熊猫:0.17%
4.长臂猿:0.07%
5. titi:0.05%
classify_image("images/space-shuttle1.jpg", "resnet")
1.航天飞机:92.38%
2.三角恐龙:7.15%
3.战机:0.11%
4.牛仔帽:0.10%
5.草帽:0.04%
classify_image("images/space-shuttle2.jpg", "resnet")
1.航天飞机:99.96%
2.导弹:0.03%
3.弹丸:0.00%
4.蒸汽机车:0.00%
5.战机:0.00%
classify_image("images/space-shuttle3.jpg", "resnet")
1.航天飞机:93.21%
2.导弹:5.53%
3.弹丸:1.26%
4.清真寺:0.00%
5.信标:0.00%
classify_image("images/space-shuttle4.jpg", "resnet")
1.航天飞机:49.61%
2.城堡:8.17%
3.起重机:6.46%
4.导弹:4.62%
5.航空母舰:4.24%
请注意,可能会出现一些错误。 例如:
classify_image("images/parrot.jpg", "inception")
1.秒表:100.00%
2.貂皮:0.00%
3.锤子:0.00%
4.黑松鸡:0.00%
5.网站:0.00%
classify_image("images/parrot.jpg", "xception")
1.背包:56.69%
2.军装:29.79%
3.围兜:8.02%
4.钱包:2.14%
5.乒乓球:1.52%
- 定义一个辅助函数,用于显示每个预构建和预训练网络的内部架构:
def print_model(model): print ("Model:",model) Network = MODELS[model][0] model = Network(weights="imagenet") model.summary() print_model('vgg19')
('Model:', 'vgg19') _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_14 (InputLayer) (None, 224, 224, 3) 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv4 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv4 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv4 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 _________________________________________________________________ flatten (Flatten) (None, 25088) 0 _________________________________________________________________ fc1 (Dense) (None, 4096) 102764544 _________________________________________________________________ fc2 (Dense) (None, 4096) 16781312 _________________________________________________________________ predictions (Dense) (None, 1000) 4097000 ================================================================= Total params: 143,667,240 Trainable params: 143,667,240 Non-trainable params: 0
工作原理
我们使用了 Keras 应用,预训练的 Keras 学习模型,该模型随预训练的权重一起提供。 这些模型可用于预测,特征提取和微调。 在这种情况下,我们将模型用于预测。 我们将在下一个秘籍中看到如何使用模型进行微调,以及如何在最初训练模型时最初不可用的数据集上构建自定义分类器。
更多
截至 2017 年 7 月,Inception-v4 尚未在 Keras 中直接提供,但可以作为单独的模块在线下载。 安装后,该模块将在首次使用时自动下载砝码。
AlexNet 是最早的堆叠式深层网络之一,它仅包含八层,前五层是卷积层,然后是全连接层。 该网络是在 2012 年提出的,明显优于第二名(前五名的错误率为 16%,而第二名的错误率为 26% )。
关于深度神经网络的最新研究主要集中在提高准确率上。 较小的 DNN 架构具有同等的准确率,至少具有三个优点:
- 较小的 CNN 在分布式训练期间需要较少的跨服务器通信。
- 较小的 CNN 需要较少的带宽才能将新模型从云导出到提供模型的位置。
- 较小的 CNN 在具有有限内存的 FPGA 和其他硬件上部署更可行。 为了提供所有这些优点,SqueezeNet 在论文 SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size 中提出。 SqueezeNet 通过减少 50 倍的参数在 ImageNet 上达到 AlexNet 级别的准确率。 此外,借助模型压缩技术,我们可以将 SqueezeNet 压缩到小于 0.5 MB(比 AlexNet 小 510 倍)。 Keras 将 SqueezeNet 作为单独的模块在线实现。
复用预建的深度学习模型来提取特征
在本秘籍中,我们将看到如何使用深度学习来提取相关特征
准备
一个非常简单的想法是通常使用 VGG16 和 DCNN 进行特征提取。 该代码通过从特定层提取特征来实现该想法。
操作步骤
我们按以下步骤进行:
- 导入处理和显示图像所需的预建模型和其他模块:
from keras.applications.vgg16 import VGG16 from keras.models import Model from keras.preprocessing import image from keras.applications.vgg16 import preprocess_input import numpy as np
- 从网络中选择一个特定的层,并获得作为输出生成的特征:
# pre-built and pre-trained deep learning VGG16 model base_model = VGG16(weights='imagenet', include_top=True) for i, layer in enumerate(base_model.layers): print (i, layer.name, layer.output_shape) # extract features from block4_pool block model = Model(input=base_model.input, output=base_model.get_layer('block4_pool').output)
- 提取给定图像的特征,如以下代码片段所示:
img_path = 'cat.jpg' img = image.load_img(img_path, target_size=(224, 224)) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x) # get the features from this block features = model.predict(x)
工作原理
现在,您可能想知道为什么我们要从 CNN 的中间层提取特征。 关键的直觉是:随着网络学会将图像分类,各层学会识别进行最终分类所必需的特征。
较低的层标识较低阶的特征(例如颜色和边缘),较高的层将这些较低阶的特征组合为较高阶的特征(例如形状或对象)。 因此,中间层具有从图像中提取重要特征的能力,并且这些特征更有可能有助于不同种类的分类。
这具有多个优点。 首先,我们可以依靠公开提供的大规模训练,并将这种学习迁移到新颖的领域。 其次,我们可以节省昂贵的大型训练时间。 第三,即使我们没有针对该领域的大量训练示例,我们也可以提供合理的解决方案。 对于手头的任务,我们也有一个很好的起始网络形状,而不是猜测它。
用于迁移学习的非常深的 InceptionV3 网络
迁移学习是一种非常强大的深度学习技术,在不同领域中有更多应用。 直觉非常简单,可以用类推来解释。 假设您想学习一种新的语言,例如西班牙语,那么从另一种语言(例如英语)已经知道的内容开始可能会很有用。
按照这种思路,计算机视觉研究人员现在通常使用经过预训练的 CNN 来生成新任务的表示形式,其中数据集可能不足以从头训练整个 CNN。 另一个常见的策略是采用经过预先训练的 ImageNet 网络,然后将整个网络微调到新颖的任务。
InceptionV3 Net 是 Google 开发的非常深入的卷积网络。 Keras 实现了整个网络,如下图所示,并且已在 ImageNet 上进行了预训练。 该模型的默认输入大小在三个通道上为299x299
:
ImageNet v3 的示例
准备
此框架示例受到 Keras 网站上在线提供的方案的启发。 我们假设在与 ImageNet 不同的域中具有训练数据集 D。 D 在输入中具有 1,024 个特征,在输出中具有 200 个类别。
操作步骤
我们可以按照以下步骤进行操作:
- 导入处理所需的预建模型和其他模块:
from keras.applications.inception_v3 import InceptionV3 from keras.preprocessing import image from keras.models import Model from keras.layers import Dense, GlobalAveragePooling2D from keras import backend as K # create the base pre-trained model base_model = InceptionV3(weights='imagenet', include_top=False)
- 我们使用训练有素的 Inception-v3,但我们不包括顶级模型,因为我们要在 D 上进行微调。顶层是具有 1,024 个输入的密集层,最后一个输出是具有 200 类输出的 softmax 密集层。
x = GlobalAveragePooling2D()(x)
用于将输入转换为密集层要处理的正确形状。 实际上,base_model.output
张量具有dim_ordering="th"
的形状(样本,通道,行,列),dim_ordering="tf"
具有(样本,行,列,通道),但是密集层需要GlobalAveragePooling2D
计算(行,列)平均值,将它们转换为(样本,通道)。 因此,如果查看最后四层(在include_top=True
中),则会看到以下形状:
# layer.name, layer.input_shape, layer.output_shape ('mixed10', [(None, 8, 8, 320), (None, 8, 8, 768), (None, 8, 8, 768), (None, 8, 8, 192)], (None, 8, 8, 2048)) ('avg_pool', (None, 8, 8, 2048), (None, 1, 1, 2048)) ('flatten', (None, 1, 1, 2048), (None, 2048)) ('predictions', (None, 2048), (None, 1000))
- 当包含
_top=False
时,将除去最后三层并暴露mixed_10
层,因此GlobalAveragePooling2D
层将(None, 8, 8, 2048)
转换为(None, 2048)
,其中(None, 2048)
张量中的每个元素都是(None, 8, 8, 2048)
张量中每个对应的(8, 8)
张量的平均值:
# add a global spatial average pooling layer x = base_model.output x = GlobalAveragePooling2D()(x) # let's add a fully-connected layer as first layer x = Dense(1024, activation='relu')(x) # and a logistic layer with 200 classes as last layer predictions = Dense(200, activation='softmax')(x) # model to train model = Model(input=base_model.input, output=predictions)
- 所有卷积级别都经过预训练,因此我们在训练完整模型时将其冻结。
# i.e. freeze all convolutional Inception-v3 layers for layer in base_model.layers: layer.trainable = False
- 然后,对模型进行编译和训练几个周期,以便对顶层进行训练:
# compile the model (should be done *after* setting layers to non-trainable) model.compile(optimizer='rmsprop', loss='categorical_crossentropy') # train the model on the new data for a few epochs model.fit_generator(...)
- 然后我们冻结 Inception 中的顶层并微调 Inception 层。 在此示例中,我们冻结了前 172 层(要调整的超参数):
# we chose to train the top 2 inception blocks, i.e. we will freeze # the first 172 layers and unfreeze the rest: for layer in model.layers[:172]: layer.trainable = False for layer in model.layers[172:]: layer.trainable = True
- 然后重新编译模型以进行微调优化。 我们需要重新编译模型,以使这些修改生效:
# we use SGD with a low learning rate from keras.optimizers import SGD model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy') # we train our model again (this time fine-tuning the top 2 inception blocks # alongside the top Dense layers model.fit_generator(...)
工作原理
现在,我们有了一个新的深度网络,该网络可以重用标准的 Inception-v3 网络,但可以通过迁移学习在新的域 D 上进行训练。 当然,有许多参数需要微调以获得良好的精度。 但是,我们现在正在通过迁移学习重新使用非常庞大的预训练网络作为起点。 这样,我们可以通过重复使用 Keras 中已经可用的内容来节省对机器进行训练的需求。
更多
截至 2017 年,“计算机视觉”问题意味着在图像中查找图案的问题可以视为已解决,并且此问题影响了我们的生活。 例如:
- 《皮肤科医师对具有深层神经网络的皮肤癌的分类》(Andre Esteva,Brett Kuprel,Roberto A. Novoa,Justin Ko,Susan M. Swetter,Helen M. Blau & Sebastian Thrun,2017 年)使用 129450 个临床图像的数据集训练 CNN,该图像由 2032 种不同疾病组成。 他们在 21 个经过董事会认证的皮肤科医生的活检验证的临床图像上对结果进行了测试,并使用了两个关键的二元分类用例:角质形成细胞癌与良性脂溢性角化病; 恶性黑色素瘤与良性痣。 CNN 在这两项任务上均达到了与所有测试过的专家相同的表现,展示了一种能够对皮肤癌进行分类的,具有与皮肤科医生相当的能力的人工智能。
- 论文《通过多视图深度卷积神经网络进行高分辨率乳腺癌筛查》(Krzysztof J. Geras,Stacey Wolfson,S。Gene Kim,Linda Moy,Kyunghyun Cho)承诺通过其创新的架构来改善乳腺癌的筛查过程,该架构可以处理四个标准视图或角度,而不会牺牲高分辨率。 与通常用于自然图像的 DCN 架构(其可处理
224 x 224
像素的图像)相反,MV-DCN 也能够使用2600 x 2000
像素的分辨率。
TensorFlow 1.x 深度学习秘籍:1~5(3)https://developer.aliyun.com/article/1426764