当前位置:   article > 正文

基于Keras、DenseNet模型微调、参数冻结、数据增强、模型训练、模型验证全流程记录(模型微调开发全流程记录)_keras densenet 第五 层 输出

keras densenet 第五 层 输出

基于DeneNet,使用keras搭建模型,用imagenet的权重进行预训练。densenet169的layers数量未595,冻结模型前593,增加一个2分类的dense层,使用图片训练。

本篇仅对模型的训练和调整步骤进行记录。对超参数的调整以及相关问题,请看后续文章。

https://blog.csdn.net/Labiod/article/details/105296184

微调模型、冻结参数

对模型进行微调之前,需要先对模型的整体框架进行一个了解。微调的层数为整个网络框架的最后的全连接层。这里使用plot_model()函数,显示出框架内的整体结构:

  1. from keras.utils import plot_model
  2. plot_model(model, to_file='../ModelImage/DenseNet169.jpg', show_shapes=True) # 使用Keras的自带库显示框架结构

修改前的模型(只截取末端的几层):

对这个模型做微调。使用基于denseNet在imageNet预训练好的权重。

步骤如下:

选取取消头部全连接层的模型作为基模型 --》 添加新的全连接层并将其与之前层连接起来 --》 冻结相应预训练参数模型 —》对新的模型进行complie

代码如下:

  1. base_model = DenseNet169(include_top=False, weights='imagenet', input_shape=(IN_WIDTH,INT_HEIGHT, 3))
  2. # dinclude_top=False 表示取消模型顶部的全连接层
  3. # weights='imagenet' 表示使用预训练的权重
  4. model = add_new_last_layer(base_model, 2)
  5. # 设置新的全连接层,并将其与之前的层数连接起来
  6. for layer in model.layers[:595]: # DenseNet169需要冻结前595
  7. layer.trainable = False # 冻结模型全连接层之前的参数
  8. model.compile(optimizer=SGD(lr=learning_rate, momentum=0.9), loss=[mycrossentropy()], metrics=['accuracy'])
  9. # 对模型进行新的编译 ,同时设定优化器、learning rate等参数

连接全连接层与base_model代码add_new_last_layer()如下:

  1. def add_new_last_layer(base_model, nb_classes, drop_rate=0.):
  2. """Add last layer to the convnet
  3. Args:
  4. base_model: keras model excluding top
  5. nb_classes: # of classes
  6. Returns:
  7. new keras model with last layer
  8. """
  9. x = base_model.output
  10. x = Dropout(0.5)(x) # 添加dropout层
  11. x = GlobalAveragePooling2D()(x) # 添加Pooling层
  12. predictions = Dense(nb_classes, activation='softmax')(x) # 添加softmax层
  13. model = Model(inputs=base_model.input, outputs=predictions) # 这一步将微调后模型的卷积层和新的softmax层连接起来
  14. return model

修改后的模型(仅保存后边几层):

 

数据增强

微调好的模型,训练数据的数量过少,使用数据增强对数据集进行扩充。

使用keras数据增强:

导入库:

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array

 设置增强方式:

  1. datagen = ImageDataGenerator(
  2. rotation_range=40,
  3. width_shift_range=0.2,
  4. height_shift_range = 0.2,
  5. shear_range=0.2,
  6. zoom_range=0.2,
  7. horizontal_flip=True,
  8. fill_mode="nearst"
  9. )

对路径下的OK路径下的数据进行增强:

  1. for img in img_OK:
  2. img = image.load_img(img)
  3. x = image.img_to_array(img) # 把PIL图像转换成一个numpy数组,形状为(3, 150, 150)
  4. x = x.reshape((1,) + x.shape) # 这是一个numpy数组,形状为 (1, 3, 150, 150)
  5. # 下面是生产图片的代码
  6. # 生产的所有图片保存在 `save_to_dir` 目录下
  7. i = 0
  8. for batch in datagen.flow(x, batch_size=32,
  9. save_to_dir='../data/DataEnhancement/OK', save_prefix='mask', save_format='jpg'):
  10. i += 1
  11. print("batch_OK: {} is in the {}", img, i)
  12. if i > 50:
  13. break # 否则生成器会退出循环

完成数据增强后,就可以得图像在各维度上变换后的数据集了。

 

训练模型

设置keras训练参数

  1. #######################################
  2. # 在训练的时候置为1
  3. from keras import backend as K
  4. K.set_learning_phase(1)
  5. #######################################

使用数据生成器生成训练集和验证集:

这里给出训练集生成器代码,验证集生成器原理类似。

  1. train_generator = train_datagen.flow_from_directory(
  2. directory = TRAIN_DIR, # 数据路径
  3. target_size = (IN_WIDTH, INT_HEIGHT), # 图片大小
  4. batch_size=BATCH_SIZE, # batch_size 一次训练所选取的样本数,
  5. class_mode='categorical',
  6. seed=2018, # 设置seed的作用可以使随机数据可以预测,即只要seed的值一样,后续生成随机数都是一样的。
  7. interpolation='box', # PIL默认插值下采样的时候会模糊
  8. # 使用PIL调整图像的大小
  9. )

使用model.fit_generator()来实现模型训练:

这一步里需要传入之前生成的训练、测试集等条件, 具体参数值,根据自己需要设定。

  1. model.fit_generator(
  2. # 当数据集比较难处理,比如,太大而无法放入内存,要求进行增强以对抗过拟合。
  3. train_generator, # fit_generator必需要传入一个生成器,我们的训练数据也是通过生成器产生的
  4. steps_per_epoch = 1*(train_generator.samples // BATCH_SIZE + 1),
  5. # 用BATCH_SIZE将原数据转换为steps_per_epoch。从generator产生的步骤的总数(样本批次总数)。
  6. # 通常情况下,应该等于数据集的样本数量除以批量的大小。
  7. epochs = EPOCHS, # 整数,在数据集上迭代的总数
  8. max_queue_size = 10, # 迭代器最大队列数,默认为10
  9. workers = 1, # 在使用基于进程的线程时,最多需要启动的进程数量。
  10. verbose = 1, # 日志显示开关。0代表不输出日志,1代表输出进度条记录,2代表每轮输出一行记录
  11. validation_data = valid_generator, # 导入验证集数据
  12. validation_steps = valid_generator.samples // BATCH_SIZE,
  13. callbacks = callbacks # 回调函数
  14. )

注意这里还需要使用keras里的回调函数(callbacks)来配置一些其它的训练策略:

使用get_callbackes传递callbacks,具体参数值,根据自己需要设定。

  1. callbacks = get_callbacks(filepath=save_model_path, patience=3)
  2. # filepath:保存模型文件的路径
  3. # patience:停止增长后训练的epoch数

get_callbackes()函数中,调用部分keras的函数方法代码如下。
具体参数值,根据自己需要设定。

  1. def get_callbacks(filepath, patience=2):
  2. lr_reduce = ReduceLROnPlateau(monitor='val_accuracy', factor=0.1, epsilon=1e-5, patience=patience, verbose=1, min_lr = 0.00001)
  3. # 该回调函数检测patience数量,如果没有看到epoch的“patience”数量的改善,那么学习率就会降低。
  4. msave = ModelCheckpoint(filepath, monitor='val_acc', save_best_only=False)
  5. # 该回调函数将在每个epoch后保存模型到filepath
  6. # save_best_only:当设置为True时,将只保存在验证集上性能最好的模型
  7. earlystop = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=patience*3+2, verbose=1, mode='auto')
  8. # 早停法是一种广泛被使用的降低过拟合的方法
  9. return [lr_reduce, msave, earlystop]

ReduceLROnPlateau()函数,当验证集精度在一定周期里不再上涨时,降低学习率。

ModelCheckpoint()函数,当检测的验证集精度达到最高时,保存模型。

EarlyStopping()函数,当验证集精度在一定周期内不再上涨后,就停止训练,防止过拟合。

最终将各种策略的返回值,传递给callback,由之前的model.fit_generator()机制,实现模型训练过程中的一些小tricks,使训练过程尽量避免泛化不足、过拟和等问题。

验证模型

 

验证模型代码如下:

  1. def predict(weights_path, IN_SIZE):
  2. '''
  3. 对测试数据进行预测
  4. '''
  5. IN_WIDTH = IN_SIZE
  6. INT_HEIGHT = IN_SIZE
  7. K.set_learning_phase(0)
  8. # 函数返回值,决定当前模型是在训练模式下,还是测试模式下。变量 1:训练模式, 0: 测试模式
  9. test_pic_root_path = '../data/data2/test'
  10. filename = []
  11. probability = [] # 可能性
  12. # 1#得到模型
  13. model = get_model(IN_SIZE) # 这个步骤最终会加载预训练好的DenseNet169
  14. model.load_weights(weights_path)
  15. # 2#预测
  16. for parent,_,files in os.walk(test_pic_root_path):
  17. # os.walk返回遍历的目录地址。不包括子目录
  18. # parent是指返回这个遍历本身的路径; _ (list),该文件夹中所有目录的名字;files(list),该文件夹中的所有文件
  19. for line in files:
  20. pic_path = os.path.join(test_pic_root_path, line.strip())
  21. ori_img = cv2.imread(pic_path)
  22. img = load_img(pic_path, target_size=(INT_HEIGHT, IN_WIDTH, 3), interpolation='box')
  23. img = img_to_array(img)
  24. # img_to_array()不管是2D shape还是3D shape image,返回都是3D Numpy array.
  25. img = preprocess_input(img)
  26. # keras中 preprocess_input() 函数完成数据预处理的工作,数据预处理能够提高算法的运行效果。
  27. # 常用的预处理包括数据归一化和白化(whitening)。
  28. img = np.expand_dims(img, axis=0)
  29. # np.expand_dims(img, axis=0)表示再0位置增加数据
  30. prediction = model.predict(img)[0]
  31. index = list(prediction).index(np.max(prediction)) # index()函数用于从列表中找出某个值第一个匹配项的索引位置
  32. pro = list(prediction)[0] # bad对应的概率大小,因为bad是在index为0的位置
  33. pro = round(pro, 5) # 将数字四舍五入为仅两个小数
  34. if pro == 0:
  35. pro = 0.00001
  36. if pro == 1:
  37. pro = 0.99999
  38. # 存入list
  39. filename.append(line.strip()) # Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
  40. probability.append(pro)
  41. #3#写入csv
  42. res_path = "../submit/submit_"+datetime.datetime.now().strftime('%Y%m%d_%H%M%S') + ".csv"
  43. dataframe = pd.DataFrame({'filename': filename, 'probability': probability})
  44. dataframe.to_csv(res_path, index=False, header=True)

到这一步基本可以完成一个完整的训练过程。源码将在后续进一步整理后更新。在调试过程中出现的一系列问题也将在后续更新。

 最终,在main()里,设置好相关路径、调用训练、验证模块,设置好超参数等信息,即可运行代码,完成训练。

训练使用环境

环境: VScode

tensorflow-gpu 2.0.0

keras  2.3.1

cuda 10.1

GPU驱动 Driver Version: 418.87.00

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/101256
推荐阅读
相关标签
  

闽ICP备14008679号