五月两场 | NVIDIA DLI 深度学习入门课程

5月19日/5月26日一天密集式学习  快速带你入门阅读全文>

正文共3152个字,预计阅读时间8分钟。

本文主要是总结之前零零散散抽出时间做的百度西交大狗狗图片分类竞赛题目 竞赛.目前本人已经彻底排到了50名后面,,,也没有想到什么办法去调优,并且平时也忙没时间再继续做.权且记录下来一些过程和心得。

综合说明

代码已经全部上传到github上,地址为:github code.大家下载的时候喜欢的话可以star下哈.

data目录没有上传,这里简单说下目录结构.与src同级的data目录下有train_data2和test1两个目录.分别是训练集和官方测试集.train_data2下是99个目录(原本是100种狗,后来发现有两种其实是一样的只是打标签打的不一样了,官方的回应是就这样了也不修改了,后续我测试发现将这两种合并下效果会略微好一点),每个目录下存放有图片.

训练过程我是将所有训练图片约20000张读入程序,而后分割出5%作为测试集.完成模型训练后去预测test1里图片的标签进而上传到官网评测.官方以错误率为评价指标.

目前本代码测试单模型最好约能到20.09,进行一些模型投票后最好到19.08.然后就再也升不上去了...

不保证运行本代码一定能得到上述我所说的我的最好结果.毕竟模型初始化啊,迭代轮数都会有影响.

主要是将代码撸一遍分析下为自己做笔记.

代码记录分析

main()函数

1if __name__=="__main__":2classnum = 993X,Y = getdata.get('../data/train_data2/')4X_train, X_test, Y_train, Y_test = train_test_split(X, Y,train_size=0.95, random_state=79)5Y_train = makeonehot(Y_train,classnum)6Y_test = makeonehot(Y_test,classnum) train(X_train,Y_train,X_test,Y_test,depoch=35,ftepoch=50,batch_size=32,classnum=classnum,out='inception.model')

首先是获取数据.使用的是getdata.py里的函数.其主要操作就是读取所有图片并将图片和标签分别存储到X,Y里去.这个没啥好说的,我代码写的比较乱,但是该有的注释还是有的,嗯。

而后使用了sklearn里的train_test_split进行了测试集合和训练集合的分割.这里取了5%作为测试集,其实是比较少的.一般来说我们做实验是至少要取20%作为测试集的,并且一般还要进行交叉验证来进行超参数选择,不过我这里都没有,原因一是我时间不多,二是跑一次程序就得一天多,很多超参数其实是我凭经验设置的,交叉验证实在是跑不起。

而后对标签进行了one_hot处理.这个keras里好像没有像tensorflow里那个sparse_crossentropy_loss的东东啊.有的话告诉我下呗。

然后就去训练了.设置了先depoch个35轮,而后ftepoch个50轮,batch_size为32张,保持的模型前缀叫inception.model等等。

train()函数

 1def train(X_train,Y_train,X_test,Y_test,depoch=50,ftepoch=201,batch_size=32,classnum=100,out='inceptionv3-ft.model'): 2"""Use transfer learning and fine-tuning to train a network on a new dataset""" 3nb_train_samples = len(Y_train) 4nb_classes = classnum 5nb_val_samples = len(Y_test) 6batch_size = batch_size 7# data prep 8train_datagen =  ImageDataGenerator( 9preprocessing_function=preprocess_input,10rotation_range=30,#角度11width_shift_range=0.2,#水平偏移12height_shift_range=0.2,#高度偏移13shear_range=0.2,#剪切强度,逆时针方向的剪切变化角度14zoom_range=0.2,#随机缩放的幅度15horizontal_flip=True,#进行随机水平反转16vertical_flip=False#进行竖直反转17)18train_generator = train_datagen.flow(X_train, Y_train, batch_size=batch_size, seed=42)19X_test = preprocess_input(X_test)20# setup model21base_model = InceptionV3(weights='imagenet', include_top=False) #include_top=False excludes final FC layer22model = add_new_last_layer(base_model, nb_classes)23# transfer learning24setup_to_transfer_learn(model, base_model)25for i in range(depoch):26print('Epoch: ',i)27model.fit_generator(train_generator,epochs=1,28            steps_per_epoch =int(nb_train_samples/batch_size),29            class_weight='auto',workers=30,max_q_size=100)30score1, acc1 = model.evaluate(X_test, Y_test,batch_size=batch_size)31print('epoch: ',i,'eval_acc: ',acc1)32# fine-tuning33setup_to_finetune(model)34for i in range(ftepoch):35print('Epoch: ',i)36model.fit_generator(train_generator,epochs=1,37            steps_per_epoch = int(nb_train_samples/batch_size),38            class_weight='auto',workers=30,max_q_size=100)39score1, acc1 = model.evaluate(X_test, Y_test, batch_size=batch_size)40print('epoch: ',i,'eval_acc: ',acc1)41if i%10 == 0 and i !=0:42model.save(out+str(i))43score, acc = model.evaluate(X_test, Y_test,batch_size=batch_size)44print('now accu:',acc)45print('ALL DONE')

首先是统计一些参数.

Keras的图片数据增强

train_datagen是训练数据生成器.这个属于是keras特有的福利了应该.我们做图像分类的时候一定要进行的一个步骤就是所谓的数据增强,也就是对原图片进行反转翻转切割放缩等变换来扩充训练数据集.而keras里则自带了这样一个增强工具.我们只需要设置好数据增强的各个参数,然后使用flow函数将原数据传入,这个生成器就会源源不断的产生从原数据增强出的数据.这样的话我们训练的时候就可以一直从这里面取出数据来作为训练集。

下面这个小坑是我自己实验总结来的,没有看keras源码,所以可能有错误,烦请大家一定提出来。

说到这里有一个小坑有必要提一下,也就是在tarin_generator=train_datagen.flow()时,传入的总数据的个数最好是能够和batch_size能够整除的,不这样做也可以,我先说说这样做的原因然后如果不这样做后续如何做大家自然就知道了。

因为datagen在生成数据时,其实是先将数据shuffle之后,挨个去取batch_size大小,直到取完这一轮或者datagen重置之后才会重新对数据shuffle而后再对数据遍历.比如说数据一共20个,batch_size设置为9,那么开始会取出2个9,在下一轮时因为只剩下2个样本而batch_size为9就会报错。

所以最好是整除关系(可以通过合理设置batch_size或者去除一部分数据使得能够整除这样的方式),那么如果不这么做呢.这里的代码其实就是一个例子.后续在使用train_generator是在这里:

1model.fit_generator(train_generator,epochs=1,2            steps_per_epoch = int(nb_train_samples/batch_size),3            class_weight='auto',workers=30,max_q_size=100)

这里没有报错,我个人感觉一是里面的steps_per_epoch计算的结果的作用是相当于把数据最后不够batch_size的给忽略掉不要了,二是可能fit_generator在每个epoch时会对里面的train_generator做类似重置这样的工作.

迁移学习模型导入及训练

接着说代码。

因为这里使用的迁移学习,也就是使用了预训练模型InceptionV3.InceptionV3是有自己的输入数据预处理方式的,所以这里对x_test也就是测试数据做了下预处理.其实上面的train_datagen里也要有这个预处理过程.并且IncepV3图片输入维度是299X299X3所以传入的X的大小也要匹配。

而后就是导入IncepV3的预训练模型.这里设置weights='imagenet'也就是说导入的模型有训练好的权重,并且这个权重是从imagenet里训练得到的.include_top=False指的是不包含最后的全连接输出层,这个是肯定是因为imagenet是1000分类而我们这里是99分类,我们只使用InceptionV3的前面部分而最后的全连接层我们自己来补充.也就是通过add_new_last_layer()这个函数,如下:

 1def add_new_last_layer(base_model, nb_classes): 2""" 3迁移学习 4""" 5x = base_model.output 6x = GlobalAveragePooling2D()(x) 7x = Dense(FC_SIZE)(x) #new FC layer, random init 8x = BatchNormalization()(x) 9x = Activation('relu')(x)10x = Dropout(0.3)(x)11predictions = Dense(nb_classes, activation='softmax')(x) #new softmax layer12model = Model(inputs=base_model.input, outputs=predictions)13return model

这里需要注意的是我使用了BN和dropout,并且dropout设置为0.3可以说是比较小,这个属于我自己实验调参感觉这样比较好。

而后就需要先训练我们刚才加的那几层了.这是迁移学习里的一个技巧,也就是我们会先冻结网络一部分去训练另外一部分,这里因为整个网络前面是InceptionV3的预训练权重,我们认为应该不错,而后面是我们自己加的层是随机初始化的,那么需要将训练几轮把新加的这几层权重也训练的差不多才行.这里我们冻结model的前面所有层,如下:

1def setup_to_transfer_learn(model, base_model):2for layer in base_model.layers:3layer.trainable = False4model.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])

然后就是训练过程了.至于训练多少轮这个看实验结果,我这里训练20-40轮都差不多,一般来说对于复杂的问题只训练这最后两层是很难达到高的准确度的,甚至训练集的准确度也提高不了多少,这其实就是欠拟合了,因为模型可调整的参数太少了,无法拟合出这么复杂的问题.不过如果是简单的问题的话有有可能只训练后面加的这几层就行了。

finetune

那么后面就是finetune了,这也是迁移学习里最重要的一步.顾名思义就是一点一点去拟合.一般我们是要看下整个网络结构,而后从后往前开始,先放开一部分层,冻结前面的,使用数据来训练后面的这几层,好了之后再往前放开一部分层,再训练,如此这样直到达到预期的目标。

我这里只进行了一次fintune,因为我发现就这一次就已经很明显的会过拟合了(训练集准确度很高而测试集准确度不升)。

1def setup_to_finetune(model):2for layer in model.layers[:NB_IV3_LAYERS_TO_FREEZE]:3layer.trainable = False4for layer in model.layers[NB_IV3_LAYERS_TO_FREEZE:]:5layer.trainable = True6model.compile(optimizer=SGD(lr=0.0001, momentum=0.9),loss='categorical_crossentropy', metrics=['accuracy'])

这里从参数看是冻结了前172层而后续的是放开了.至于这个172是如何得知一般我们是要看下Inception的结构,其结构一般是分层次的,每个层次包含多少多少层,通常我们倾向于以它的这个结构上的层次为划分一步一步去解冻去finetune。

然后就还是训练过程了.这里每10轮保存下模型.主要是为了后续的投票机制.

结尾

到这里基本就完了.想要提高模型效果的话就是不断的调参和上trick去测试了。

有一个技巧很多提到就是使用centerloss,这个原理的话可以参考我一篇博客centerloss.不过目前我只在tensorflow上写这个centerloss,keras好像封装的很深我目前没有太深入了解keras还真实现不出来...那篇博客可以是一个原理性的解释和说明这样的。

原文链接:https://www.jianshu.com/p/3fbc6f6a36cc

查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:

www.leadai.org

请关注人工智能LeadAI公众号,查看更多专业文章

大家都在看

LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理(一)

最全常见算法工程师面试题目整理(二)

TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础

宠物狗图片分类之迁移学习代码笔记相关推荐

  1. 迁移学习后续——中草药分类(之简单学习代码编程过程)

    文章目录 特征提取代码 训练测试代码 全连接层模型保存代码 图片预测展示 简易迁移学习代码(万金油代码) 此代码是对上篇代码编写的一个简单的心路历程以及代码.模型,数据集与上篇一致没有变,这边用了五个 ...

  2. 迁移学习——入门笔记

    一.简介 背景: 现如今数据爆炸: 对机器学习模型来说要求快速构建,强泛化 对于数据来说,大部分数据没有标签 所以收集标签数据和从头开始构建一个模型都是代价高昂的,需要对模型和带有标签的数据进行重用 ...

  3. CSDN技术主题月----“深度学习”代码笔记专栏

    from: CSDN技术主题月----"深度学习"代码笔记专栏 2016-09-13 nigelyq 技术专题 Hi,各位用户 CSDN技术主题月代码笔记专栏会每月在CODE博客为 ...

  4. 使用Flow forecast进行时间序列预测和分类的迁移学习介绍

    ImageNet首次发表于2009年,在接下来的四年里,它成为了大多数计算机视觉模型的基础.到目前为止,无论您是在训练一个模型来检测肺炎还是对汽车模型进行分类,您都可能从在ImageNet或其他大型( ...

  5. Pytorch机器学习/深度学习代码笔记

    代码步骤笔记 导入模块 设置参数 数据预处理 定义数据集 1.Dataset 2.ImageFolder 加载数据集 DataLoader torchvision--数据预处理要使用的库 torchv ...

  6. 迁移学习和finetune的区别及迁移学习代码实现

    转载:https://blog.csdn.net/gentelyang/article/details/77512565 一:区别 1:迁移学习是将已经学习到的知识应用到其他领域,比如通用的语音模型迁 ...

  7. 周纵苇——三维迁移学习报告笔记

    最近自己会把自己个人博客中的文章陆陆续续的复制到CSDN上来,欢迎大家关注我的 个人博客,以及我的github. 本文主要是记录周纵苇(U-Net++的作者)大神关于三维迁移学习的报告的笔记.原文请参 ...

  8. [强化学习代码笔记]Python复习

    文章目录 Python复习 1. 介绍 2. 编写规范 3. 基本语法 一切都是对象 查看帮助 空/否定 保留字 as assert del try...except...finally global ...

  9. 【基础论文笔记二】Transfer Learning with Dynamic AdversarialAdaptation Network(2019 ICDM)动态对抗适应网络的迁移学习论文笔记

    背景 现有的对抗性领域自适应方法要么学习单个领域鉴别器来对齐全局源和目标分布,要么关注基于多个鉴别器的子域对齐.然而,在实际应用中,域之间的边际(全局)分布和条件(局部)分布对适应的贡献往往不同.在本 ...

最新文章

  1. Django1.11 扩展User属性增加头像上传功能
  2. python中进制_python中进制的算法
  3. Java---定义一个圆(Circle)类表示三维空间中的圆(两个成员变量:圆心Point类、半径)
  4. VC++2019 使用wininet下载文件
  5. helm search搜索charts命令
  6. 浅析linux下的条件变量
  7. 信息学奥赛一本通 1397:简单算术表达式求值 | OpenJudge NOI 1.12 01:简单算术表达式求值
  8. Adobe AIR简单的缓存技术
  9. 一文通俗理解最大似然估计· 看不懂你打我,无公式
  10. RC电路 CR电路 理解
  11. 利用Calendar类制作日历
  12. 2020 奇安信前端秋招笔试选择题
  13. 刘邦韩信java_刘邦为什么叫韩信雏儿 刘邦杀韩信后悔了吗
  14. python中面向对象的缺点_python中的面向对象和面向过程
  15. python图像处理:全景图片转鱼眼图片(鱼眼矫正)
  16. 又又又被段永平加仓,是时候抄底腾讯了吗?
  17. 疫情过后,哪些互联网行业将迎来发展机遇
  18. label标签使用方法
  19. MOS管应用之外接电源和电池供电的双电源自动切换电路
  20. 【趣学算法】神奇的兔子序列(斐波那契数列)

热门文章

  1. matlab改变矩阵的元素,Matlab中元素不变情况下改变矩阵形态——reshape()
  2. fit函数 model_深度学习与Tensorflow学习笔记2 ——回调函数callbacks和Tensorboard
  3. php 遍历所有网站网址,使用selenium获取网址所加载所有资源url列表信息
  4. django框架 day09
  5. 汉字转拼音,一二级词库,不支持多音字
  6. Linux性能监测(系统监测统计命令详解)
  7. Html input 标签
  8. 读大道至简第二章感悟
  9. wp8.1 页面返回 页面导航
  10. OSI七层模型及应用