参考:迁移学习——Fine-tunepython
1、迁移学习git
就是把已训练好的模型参数迁移到新的模型来帮助新模型训练。网络
模型的训练与预测:
深度学习的模型能够划分为 训练 和 预测 两个阶段。
训练 分为两种策略:一种是白手起家从头搭建模型进行训练,一种是经过预训练模型进行训练。
预测 相对简单,直接用已经训练好的模型对数据集进行预测便可。app
优势:性能
1)站在巨人的肩膀上:前人花很大精力训练出来的模型在大几率上会比你本身从零开始搭的模型要强悍,没有必要重复造轮子。
2)训练成本能够很低:若是采用导出特征向量的方法进行迁移学习,后期的训练成本很是低,用CPU都彻底无压力,没有深度学习机器也能够作。
3)适用于小数据集:对于数据集自己很小(几千张图片)的状况,从头开始训练具备几千万参数的大型神经网络是不现实的,由于越大的模型对数据量的要求越大,过拟合没法避免。这时候若是还想用上大型神经网络的超强特征提取能力,只能靠迁移学习。学习
迁移学习的几种方式:测试
一、Transfer Learning:冻结预训练模型的所有卷积层,只训练本身定制的全链接层。spa
二、Extract Feature Vector:先计算出预训练模型的卷积层对全部训练和测试数据的特征向量,而后抛开预训练模型,只训练本身定制的简配版全链接网络。
三、Fine-tune:冻结预训练模型的部分卷积层(一般是靠近输入的多数卷积层),训练剩下的卷积层(一般是靠近输出的部分卷积层)和全链接层。
* 注:Transfer Learning关心的问题是:什么是“知识”以及如何更好地运用以前获得的“知识”,这能够有不少方法和手段,eg:SVM,贝叶斯,CNN等。.net
而fine-tune只是其中的一种手段,更经常使用于形容迁移学习的后期微调中。rest
三种迁移学习方式对比
一、第一种和第二种训练获得的模型本质上并无什么区别,可是第二种的计算复杂度要远远优于第一种。
二、第三种是对前两种方法的补充,以进一步提高模型性能。要注意的是,这种方法并不必定能真的对模型有所提高。
本质上来说:这三种迁移学习的方式都是为了让预训练模型可以胜任新数据集的识别工做,可以让预训练模型本来的特征提取能力获得充分的释放和利用。可是,在此基础上若是想让模型可以达到更低的Loss,那么光靠迁移学习是不够的,靠的更多的仍是模型的结构以及新数据集的丰富程度。
2、实验:尝试对模型进行微调,以进一步提高模型性能
一、fine-tune的做用:
拿到新数据集,先用预训练模型处理,一般用上面的方法一或方法二测试预训练模型在新数据上的表现,若是表现不错,能够尝试fine-tune,进一步解锁卷积层以继续训练。
可是不要期待质的飞跃,另外,若是因为新数据集与原数据集差异太大致使表现不好,一方面能够考虑从头训练,另外一方面也能够考虑解锁比较多层的训练。
二、不一样数据集下使用微调
数据集1:数据量少,但数据类似度很是高
在这种状况下,咱们所作的只是修改最后几层或最终的softmax图层的输出类别,方法一
数据集2:数据量少,数据类似度低
在这种状况下,咱们能够冻结预训练模型的初始层(好比k层),并再次训练剩余的(n-k)层。因为新数据集的类似度较低,所以根据新数据集对较高层进行从新训练具备重要意义。方法三
数据集3:数据量大,数据类似度低
在这种状况下,因为咱们有一个大的数据集,咱们的神经网络训练将会颇有效。可是,因为咱们的数据与用于训练咱们的预训练模型的数据相比有很大不一样。使用预训练模型进行的预测不会有效。所以,最好根据你的数据从头开始训练神经网络(Training from scatch)。
数据集4:数据量大,类似度高
这是理想状况。在这种状况下,预训练模型应该是最有效的。使用模型的最好方法是保留模型的体系结构和模型的初始权重。而后,咱们可使用在预先训练的模型中的权重来从新训练该模型。
3.微调的注意事项
1)一般的作法是截断预先训练好的网络的最后一层(softmax层),并用与咱们本身的问题相关的新的softmax层替换它。
2)使用较小的学习率来训练网络。
3)若是数据集数量过少,咱们进来只训练最后一层,若是数据集数量中等,冻结预训练网络的前几层的权重也是一种常见作法。
注:卷积神经网络的核心是:
(1)浅层卷积层提取基础特征,好比边缘,轮廓等基础特征。
(2)深层卷积层提取抽象特征,好比整个脸型。
(3)全链接层根据特征组合进行评分分类。
四、实验操做具体步骤
一、下载预训练模型
二、预处理:按照预训练模型本来的预处理方式对数据进行预处理,使用预训练模型必定要确保让待训练的数据尽量向原数据集靠拢,这样才能最大程度发挥模型的识图本领。
三、基模型和定制模型:构建和预训练里面彻底相同的模型。
四、查看固定和恢复节点名
五、训练过程设置恢复,固定张量的列表
3、代码详情
基模型和定制模型
import slim.nets.resnet_v1 as resnet_v1 # 定义模型,由于给出的只有参数,并无模型,这里须要指定模型的具体结构 with slim.arg_scope(resnet_v1.resnet_arg_scope()): # logits就是最后预测值,images就是输入数据,指定num_classes=None是为了使resnet模型最后的输出层禁用 logits, end_points = resnet_v1.resnet_v1_50(inputs=input_images, num_classes=None) # 自定义的输出层 with tf.variable_scope("Logits"): # 将原始模型的输出数据去掉维度为2和3的维度,最后只剩维度1的batch数和维度4的300*300*3 # 也就是将原来的二三四维度所有压缩到第四维度 net = tf.squeeze(logits, axis=[1, 2]) # 加入一层dropout层 net = slim.dropout(net, keep_prob=0.5, scope='dropout_scope') # 加入一层全链接层,指定最后输出大小 logits = slim.fully_connected(net, num_outputs=labels_nums, scope='fc')
查看固定和恢复节点名
look_checkpoint.py
import os from tensorflow.python import pywrap_tensorflow model_dir = os.getcwd() # 获取当前文件工做路径 print(model_dir)#输出当前工做路径 checkpoint_path = r'G:\1-modelused\Siamese_Densenet_Single_Net\output\640model\model3/model_epoch_20.ckpt'#model_dir + "\\ckpt_dir\\model-ckpt-100" print(checkpoint_path)#输出读取的文件路径 # 从checkpoint文件中读取参数 reader = pywrap_tensorflow.NewCheckpointReader(checkpoint_path) var_to_shape_map = reader.get_variable_to_shape_map() # 输出变量名称及变量值 for key in var_to_shape_map: # if key.startswith('DenseNet_121/AuxLogits'): # print(1) # print(key) print("tensor_name: ", key)
训练过程设置恢复,固定张量的列表
CKPT_FILE = r'.\pretrain\resnet_v1_50.ckpt' #不须要从谷歌训练好的模型中加载的参数。这里就是最后的全链接层,由于在新的问题中要从新训练这一层中的参数。 #这里给出的是参数的前缀 CHECKPOINT_EXCLUDE_SCOPES = 'Logits' ## 指定最后的全链接层为可训练的参数,须要训练的网络层参数名称,在fine-tuning的过程当中就是最后的全链接层 TRAINABLE_SCOPES = 'Logits' #获取全部须要从谷歌训练好的模型中加载的参数 def get_tuned_variables(): exclusions = [scope.strip() for scope in CHECKPOINT_EXCLUDE_SCOPES.split(',')] variables_to_restore = [] #枚举inception-v3模型中全部的参数,而后判断是否须要从加载列表中移除 for var in slim.get_model_variables(): excluded = False for exclusion in exclusions: if var.op.name.startswith(exclusion): excluded = True break if not excluded: variables_to_restore.append(var) return variables_to_restore #获取全部须要训练的变量列表。 def get_trainable_variables(): scopes = [scope.strip() for scope in TRAINABLE_SCOPES.split(',')] variables_to_train = [] #枚举全部须要训练的参数前缀,并经过这些前缀找到全部的参数。 for scope in scopes: variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,scope) variables_to_train.extend(variables) return variables_to_train #定义加载Google训练好的Inception-v3模型的Saver load_fn = slim.assign_from_checkpoint_fn( CKPT_FILE, get_tuned_variables(), ignore_missing_vars=True ) saver = tf.train.Saver(max_to_keep=100) max_acc = 0.0 with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state('models/resnet_v1/') if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path): saver.restore(sess, ckpt.model_checkpoint_path) else: sess.run(tf.global_variables_initializer()) sess.run(tf.local_variables_initializer()) # 加载谷歌已经训练好的模型 print('Loading tuned variables from %s' % CKPT_FILE) load_fn(sess)