1. 迁移学习

2. 预训练模型

3. 使用预训练模型

4. 运用预训练模型

? 提取特征(extractfeatures)

? 优化模型(finetune the model)

5. 优化模型的方式

6. 在数字识别中使用预训练模型

? 只针对输出密集层(outputdense layer)的重新训练

? 冻结初始几层网络的权重因子

1什么是迁移学习?

我们知道,神经网络需要用数据来训练,它从数据中获得信息,进而把它们转换成相应的权重。这些权重能够被提取出来,迁移到其他的神经网络中,我们“迁移”了这些学来的特征,就不需要从零开始训练一个神经网络了。

现在,让我们从自身进化的角度来讨论这种迁移学习的重要性。这是Tim Urban最近在waitbutwhy.com上的一篇文章中提出的观点。

2. 什么是预训练模型?

简单来说,预训练模型(pre-trained model)是前人为了解决类似问题所创造出来的模型。你在解决问题的时候,不用从零开始训练一个新模型,可以从在类似问题中训练过的模型入手。

比如说,如果你想做一辆自动驾驶汽车,可以花数年时间从零开始构建一个性能优良的图像识别算法,也可以从Google在ImageNet数据集上训练得到的inception model(一个预训练模型)起步,来识别图像。

一个预训练模型可能对于你的应用中并不是100%的准确对口,但是它可以为你节省大量功夫。

接下来,我会举个例子来说明。

3. 为什么我们要用预训练模型?

上周我一直在尝试解决Crowdanalytix platform上的一个问题:从手机图片中分辨场景。

这是一个图像分类的问题,训练数据集中有4591张图片,测试集中有1200张图片。我们的任务是将图片相应地分到16个类别中。在对图片进行一些预处理后,我首先采用一个简单的MLP(Multi-laterPerceptron)模型,结构如下图所示:

在对输入图片(224*224*3)平整化后,为了简化上述结构,我用了三个各含有500个神经元的隐藏层。在输出层中,共有16个神经元对应着十六个类别。

我只能将训练的准确率控制在6.8%,这是个很不理想的结果。我尝试对隐藏层、隐层中神经元的数量以及drop out速率进行调整,但准确度都没有太大的提升。而如果增加隐藏层和其中神经元的数量,每个周期的运行时间则会增加20s以上。(我的开发环境是12GBVRAM,Titan X GPU)

下面是我用上文所述结构的MLP模型训练输出的结果。

可以看出,除非指数级地增加训练时长,MLP模型无法提供给我更好的结果。因此,我转而采用CNN(卷积神经网络),看看他们在这个数据集上的表现,以及是否能够提高训练的准确度。

CNN的结构如下:

我使用了3个卷积的模块,每个模块由以下部分组成:

·    32个5*5的filter

·    线性整流函数(ReLU)作为激活函数

·    4*4的最大值池化层

最后一个卷积模块输出的结果经过平整化后会被传递到一个拥有64的神经元的隐藏层上,随后通过一个drop out rate = 0.5处理后传递到输出层。

最终训练的结果记录如下:

准确率15.75%,尽管与MLP模型相比有所提升,但每个周期的运行时间也增加了。

而更重要的是,数据集中最大类别所含图片数量约占总数17.6%左右。

只要把所有的图片都归到最大的类别,我们就能够得到比MLP、CNN训练出来的模型更好的结果(ノへ ̄、)。

此外,增加更多的卷积模块也会大大增加训练时长。

于是,我转而去采用预训练模型,这样我不需要重新训练我的整个结构,只需要针对其中的几层进行训练即可。

因此,我采用了在ImageNet数据集上预先训练好的VGG16模型,这个模型可以在Keras库中找到。

模型的结构如下所示:

在VGG16结构的基础上,我只将softmax层的1000个输出改为16个,从而适应我们这个问题的情景,随后重新训练了dense layer。

导入必要的库

from keras.models import Sequential

from keras.layers.core import Flatten, Dense, Dropout

from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D

from keras.optimizers import SGD

import cv2, numpy as np

·        1

·        2

·        3

·        4

·        5

  • 1
  • 2
  • 3
  • 4
  • 5

UsingTheano backend.

D:\Anaconda\lib\site-packages\theano-0.8.0.dev0-py2.7.egg\theano\tensor\signal\downsample.py:5:UserWarning: downsample module has been moved to the pool module.

warnings.warn("downsample module hasbeen moved to the pool module.")

使用keras建立vgg16模型

def VGG_16(weights_path=None):

model = Sequential()

model.add(ZeroPadding2D((1,1),input_shape=(3,224,224)))

model.add(Convolution2D(64, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(64, 3, 3, activation='relu'))

model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(128, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(128, 3, 3, activation='relu'))

model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(256, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(256, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(256, 3, 3, activation='relu'))

model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(ZeroPadding2D((1,1)))

model.add(Convolution2D(512, 3, 3, activation='relu'))

model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(Flatten())

model.add(Dense(4096, activation='relu'))

model.add(Dropout(0.5))

model.add(Dense(4096, activation='relu'))

model.add(Dropout(0.5))

model.add(Dense(1000, activation='softmax'))

if weights_path:

model.load_weights(weights_path)

return model

另一段代码中:

model = VGG_16('vgg16_weights.h5')

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)

model.compile(optimizer=sgd, loss='categorical_crossentropy')

现在我们开始来预测了

首先写一个方法来加载并处理图片

def load_image(imageurl):

im = cv2.resize(cv2.imread(imageurl),(224,224)).astype(np.float32)

im[:,:,0] -= 103.939

im[:,:,1] -= 116.779

im[:,:,2] -= 123.68

im = im.transpose((2,0,1))

im = np.expand_dims(im,axis=0)

return im

·

读取vgg16的类别文件

f = open('synset_words.txt','r')

lines = f.readlines()

f.close()

·

def predict(url):

im = load_image(url)

pre = np.argmax(model.predict(im))

print lines[pre]

%pylab inline

Populatingthe interactive namespace from numpy and matplotlib

from IPython.display import Image

Image('cat1.jpg')

跟MLP和CNN相比,这个结构的准确率能够达到70%。同时,使用VGG16最大的好处是大大减少了训练时间,只需要针对dense layer进行训练,所需时间基本可以忽略。

4.怎样使用预训练模型?

当在训练经网络的时候我们的目标是什么?我们希望网络能够在多次正向反向迭代的过程中,找到合适的权重。

通过使用之前在大数据集上经过训练的预训练模型,我们可以直接使用相应的结构和权重,将它们应用到我们正在面对的问题上。这被称作是“迁移学习”,即将预训练的模型“迁移”到我们正在应对的特定问题中。

在选择预训练模型的时候你需要非常仔细,如果你的问题与预训练模型训练情景下有很大的出入,那么模型所得到的预测结果将会非常不准确。

举例来说,如果把一个原本用于语音识别的模型用来做用户识别,那结果肯定是不理想的。

幸运的是,Keras库中有许多这类预训练的结构。

ImageNet数据集已经被广泛用作训练集,因为它规模足够大(包括120万张图片),有助于训练普适模型。ImageNet的训练目标,是将所有的图片正确地划分到1000个分类条目下。这1000个分类基本上都来源于我们的日常生活,比如说猫猫狗狗的种类,各种家庭用品,日常通勤工具等等。

在迁移学习中,这些预训练的网络对于ImageNet数据集外的图片也表现出了很好的泛化性能。

既然预训练模型已经训练得很好,我们就不会在短时间内去修改过多的权重,在迁移学习中用到它的时候,往往只是进行微调(fine tune)。

在修改模型的过程中,我们通过会采用比一般训练模型更低的学习速率。

5.微调模型的方法

特征提取

我们可以将预训练模型当做特征提取装置来使用。具体的做法是,将输出层去掉,然后将剩下的整个网络当做一个固定的特征提取机,从而应用到新的数据集中。

采用预训练模型的结构

我们还可以采用预训练模型的结构,但先将所有的权重随机化,然后依据自己的数据集进行训练。

训练特定层,冻结其他层

另一种使用预训练模型的方法是对它进行部分的训练。具体的做法是,将模型起始的一些层的权重保持不变,重新训练后面的层,得到新的权重。在这个过程中,我们可以多次进行尝试,从而能够依据结果找到frozen layers和retrain layers之间的最佳搭配。

如何使用与训练模型,是由数据集大小和新旧数据集(预训练的数据集和我们要解决的数据集)之间数据的相似度来决定的。

下图表展示了在各种情况下应该如何使用预训练模型:

场景一:数据集小,数据相似度高(与pre-trained model的训练数据相比而言)

在这种情况下,因为数据与预训练模型的训练数据相似度很高,因此我们不需要重新训练模型。我们只需要将输出层改制成符合问题情境下的结构就好。

我们使用预处理模型作为模式提取器。

比如说我们使用在ImageNet上训练的模型来辨认一组新照片中的小猫小狗。在这里,需要被辨认的图片与ImageNet库中的图片类似,但是我们的输出结果中只需要两项——猫或者狗。

在这个例子中,我们需要做的就是把dense layer和最终softmax layer的输出从1000个类别改为2个类别。

场景二:数据集小,数据相似度不高

在这种情况下,我们可以冻结预训练模型中的前k个层中的权重,然后重新训练后面的n-k个层,当然最后一层也需要根据相应的输出格式来进行修改。

因为数据的相似度不高,重新训练的过程就变得非常关键。而新数据集大小的不足,则是通过冻结预训练模型的前k层进行弥补。

场景三:数据集大,数据相似度不高

在这种情况下,因为我们有一个很大的数据集,所以神经网络的训练过程将会比较有效率。然而,因为实际数据与预训练模型的训练数据之间存在很大差异,采用预训练模型将不会是一种高效的方式。

因此最好的方法还是将预处理模型中的权重全都初始化后在新数据集的基础上重头开始训练。

场景四:数据集大,数据相似度高

这就是最理想的情况,采用预训练模型会变得非常高效。最好的运用方式是保持模型原有的结构和初始权重不变,随后在新数据集的基础上重新训练。

6. 在手写数字识别中使用预训练模型

现在,让我们尝试来用预训练模型去解决一个简单的问题。

我曾经使用vgg16作为预训练的模型结构,并把它应用到手写数字识别上。

让我们先来看看这个问题对应着之前四种场景中的哪一种。我们的训练集(MNIST)有大约60,000张左右的手写数字图片,这样的数据集显然是偏小的。所以这个问题应该属于场景一或场景二。

我们可以尝试把两种对应的方法都用一下,看看最终的效果。

只重新训练输出层 & dense layer

这里我们采用vgg16作为特征提取器。随后这些特征,会被传递到依据我们数据集训练的denselayer上。输出层同样由与我们问题相对应的softmax层函数所取代。

在vgg16中,输出层是一个拥有1000个类别的softmax层。我们把这层去掉,换上一层只有10个类别的softmax层。我们只训练这些层,然后就进行数字识别的尝试。

冻结最初几层网络的权重

这里我们将会把vgg16网络的前8层进行冻结,然后对后面的网络重新进行训练。这么做是因为最初的几层网络捕获的是曲线、边缘这种普遍的特征,这跟我们的问题是相关的。我们想要保证这些权重不变,让网络在学习过程中重点关注这个数据集特有的一些特征,从而对后面的网络进行调整。

VGG16预训练学习笔记相关推荐

  1. Keras深度学习使用VGG16预训练神经网络实现猫狗分类

    Keras深度学习使用VGG16预训练神经网络实现猫狗分类 最近刚刚接触深度学习不久,而Keras呢,是在众多的深度学习框架中,最适合上手的,而猫狗的图像分类呢,也算是计算机视觉中的一个经典案例,下面 ...

  2. BERT预训练模型学习笔记

    1.Transforme 1.1 要做一件什么事 基本组成依旧是机器翻译模型中常见的Seq2Seq网络 输入输出都很直观,其核心架构就是中间的网络设计了 MxN,输入M,输出N 1.2 传统的RNN网 ...

  3. BERT 预训练学习(数据:样本构建、输入格式;算法:transformer、mlm和nsp任务)

    任务:MLM完形填空.下一句预测 数据:构建样本数据及label,输入格式 参考: 1)**https://github.com/DA-southampton/TRM_tutorial/tree/ma ...

  4. 功放与预失真学习笔记

    功放与预失真学习 1.1 功放特性 如图1-1-1所示:其明显的特点是输出随输入有单调递增的特性(在输入饱和以前),但随着输入的增大,输出趋于饱和. 如图所示, P1dB 为功放的 1dB 压缩点,它 ...

  5. 技术调研/预研 学习笔记

    技术方向需要通过 技术调研,技术预研来帮助团队成员逐步认识,理解和明确: 这是一个必然的过程,技术团队领导应充分充实并直接参与. 技术调研 技术调研 针对粗粒度需求实现方案进行的研究,可能所有需求不太 ...

  6. torch分布式训练学习笔记

    分布式通讯包 - torch.distributed 基本 初始化 TCP初始化 共享文件系统初始化 环境变量初始化 组 点对点通信 集体功能 torch.distributed提供了一种类似MPI的 ...

  7. 《预训练周刊》第39期: 深度模型、提示学习

    No.39 智源社区 预训练组 预 训 练 研究 观点 资源 活动 周刊订阅 告诉大家一个好消息,<预训练周刊>已经开启"订阅功能",以后我们会向您自动推送最新版的&l ...

  8. 《预训练周刊》第25期:HyperCLOVA:数十亿级韩语生成式预训练变换器、GPT-3在生物医学领域不是好的小样本学习器...

    No.25 智源社区 预训练组 预 训 练 研究 观点 资源 活动 关于周刊 超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第25期&l ...

  9. 《预训练周刊》第21期:FlipDA:有效且稳健的数据增强小样本学习、开放域低资源适应的生成式聊天机器人...

    No.21 智源社区 预训练组 预 训 练 研究 观点 资源 活动 关于周刊 超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第21期&l ...

最新文章

  1. python opencv多边形掩膜
  2. 成功跳槽百度工资从15K涨到28K,专题解析
  3. 09Mybatis_入门程序——删除用户以及更新用户
  4. 程序员的你是否熟练掌握Chrome开发者工具?
  5. MySQL全文索引模糊查询_mysql全文索引之模糊查询
  6. 科普文:服务器上如何 Node 多版本共存 #31
  7. css 3d魔方源代码,CSS3 3D环境实现立体 魔方效果代码(示例代码)
  8. [kuangbin带你飞]专题九 连通图
  9. Atitit 外包管理规范attilax总结
  10. react中对于key值的理解
  11. 阿里云无影云电脑千万级补贴,助力广东企业居家办公
  12. 计算机论文的技术路线图,怎么写好论文开题报告技术路线流程图
  13. SSL 域名证书 安装指引
  14. 2020年第二届全国高校计算机能力挑战赛Excel模拟题
  15. javascript 实现在线多币种汇率实时换算
  16. 对付木马:空手入白刃谁动了我的电脑系统(转)
  17. 本地调试微信之内网穿透 ngrok/frp
  18. 克隆linux系统之后如何配置网络ip
  19. IMWebConf 2016总结
  20. java 设计模式 路由器_Java设计模式——工厂模式

热门文章

  1. 如何计算EEG信号的香农熵Shannon entropy(附Matlab程序)
  2. 爬虫一 requests库与BeautifulSoup库、HTML
  3. Maven发布轻量二方包
  4. 移动应用程序和网页应用程序_如何不完全破坏您的移动应用程序的用户界面
  5. highCharts图表应用-模拟心电图
  6. 使用ADB工具卸载/停用Android系统应用(无需Root)
  7. X710网卡RSS对称哈希
  8. Flask开发微电影网站(八)
  9. 致敬贝叶斯以及自己对贝叶斯的一些见解
  10. utf8和utf8mb4的区别