Keras之 使用keras实现resnet50模型做迁移学习-finetune

时间:2024-03-17 22:45:38

  本文将介绍:

  使用keras实现resnet50模型

  实现迁移学习-finetune

  一,下载kaggle-10monkey数据

  下载dataset到本地目录intput中

  二,使用keras中ImageDataGenerator读取数据、数据增强

  1,使用keras中ImageDataGenerator读取数据、数据增强

  #!/usr/bin/env python3

  # -*- coding: utf-8 -*-

  import matplotlib as mpl

  import matplotlib.pyplot as plt

  import numpy as np

  import os

  import pandas as pd

  import sklearn

  import sys

  import tensorflow as tf

  import time

  from tensorflow import keras

  # 打印使用的python库的版本信息

  print(tf.__version__)

  print(sys.version_info)

  for module in mpl, np, pd, sklearn, tf, keras:

  print(module.__name__, module.__version__)

  # 1,实现tensorflow动态按需分配GPU

  from tensorflow.compat.v1 import ConfigProto

  from tensorflow.compat.v1 import InteractiveSession

  config = ConfigProto()

  config.gpu_options.allow_growth = True

  session = InteractiveSession(config=config)

  # 常量的定义

  train_dir = "./input/training/training"

  valid_dir = "./input/validation/validation"

  label_file = "./input/monkey_labels.txt"

  print(os.path.exists(train_dir))

  print(os.path.exists(valid_dir))

  print(os.path.exists(label_file))

  print(os.listdir(train_dir))

  print(os.listdir(valid_dir))

  # 查看打印出来的label值

  labels = pd.read_csv(label_file, header=0)

  print(labels)

  # 定义常量

  height = 224 # resne50的处理的图片大小

  width = 224 # resne50的处理的图片大小

  channels = 3

  batch_size = 24 # 因为处理的图片变大,batch_size变小一点 32->24

  num_classes = 10

  # 一,使用keras中ImageDataGenerator读取数据

  # 1,实例化ImageDataGenerator

  # 对于图片数据,在keras里有更高层的封装.读取数据且做数据增强 -> Generator

  train_datagen = keras.preprocessing.image.ImageDataGenerator(

  preprocessing_function = keras.applications.resnet50.preprocess_input,# 此函数是是现在keras中,而非tf.keras中,在tf中,实现数据做归一化,数据取值在-1~1之间.

  # rescale = 1./255, # 由于preprocessing_function已做了归一化,此处注释; 图像中的每个像素点都是在0~255之间,得到一个0~1之间的数

  rotation_range = 40, # 图片增强的方法,把图片随机旋转一个角度,旋转的角度就在-40~40之间

  width_shift_range = 0.2, # 做水平位移 - 增加位移鲁棒性(如果0~1之间则位移比例随机选数做位移;如果大于1,则是具体的像素大小)

  height_shift_range = 0.2, # 做垂直位移 - 增加位移鲁棒性(如果0~1之间则位移比例随机选数做位移;如果大于1,则是具体的像素大小)

  shear_range = 0.2, # 剪切强度

  zoom_range = 0.2, # 缩放强度

  horizontal_flip = True, # 是否随机做水平翻转

  fill_mode = \'nearest\', # 填充像素规则,用离其最近的像素点做填充

  )

  # 2,使用ImageDataGenerator读取图片

  # 从训练集的文件夹中读取图片

  train_generator = train_datagen.flow_from_directory(train_dir,# 图片的文件夹位置

  target_size = (height, width),# 将图片缩放到的大小

  batch_size = batch_size, # 多少张为一组

  seed = 7,#随机数种子

  shuffle = True,# 是否做混插

  class_mode = "categorical") # 控制目标值label的形式-选择onehot编码后的形式

  # 从验证集的文件夹中读取图片

  valid_datagen = keras.preprocessing.image.ImageDataGenerator(

  preprocessing_function = keras.applications.resnet50.preprocess_input)

  valid_generator = valid_datagen.flow_from_directory(valid_dir,

  target_size = (height, width),

  batch_size = batch_size,

  seed = 7,

  shuffle = False,

  class_mode = "categorical")

  2,查看训练家和验证集分别有多少张数据

  train_num = train_generator.samples

  valid_num = valid_generator.samples

  print(train_num, valid_num)

  3,如何从ImageDataGenerator中读取数据

  for i in range(1):

  x, y = train_generator.next()

  print(x.shape, y.shape)

  print(y)

  三,定义模型

  1,定义ResNet50中50层初始化参数均不变

  resnet50_fine_tune = keras.models.Sequential()

  resnet50_fine_tune.add(keras.applications.ResNet50(include_top = False, # 网络结构的最后一层,resnet50有1000类,去掉最后一层

  pooling = \'avg\', #resnet50模型倒数第二层的输出是三维矩阵-卷积层的输出,做pooling或展平

  weights = \'imagenet\')) # 参数有两种imagenet和None,None为从头开始训练,imagenet为从网络下载已训练好的模型开始训练

  resnet50_fine_tune.add(keras.layers.Dense(num_classes, activation = \'softmax\')) # 因为include_top = False,所以需要自己定义最后一层

  resnet50_fine_tune.layers[0].trainable = False # 因为参数是从imagenet初始化的,所以我们可以只调整最后一层的参数

  resnet50_fine_tune.compile(loss="categorical_crossentropy",

  optimizer="sgd", metrics=[\'accuracy\']) #对于微调-finetune来说,优化器使用sgd来说更好一些

  resnet50_fine_tune.summary()

  2,定义ResNet50中后5层初始化参数变化

  plot_learning_curves(history, \'accuracy\', epochs, 0, 1)

  plot_learning_curves(history, \'loss\', epochs, 0, 2)

  #

  resnet50 = keras.applications.ResNet50(include_top = False,

  pooling = \'avg\',

  weights = \'imagenet\')

  resnet50.summary()

  #

  for layer in resnet50.layers[0:-5]:

  layer.trainable = False

  resnet50_new = keras.models.Sequential([

  resnet50,

  keras.layers.Dense(num_classes, activation = \'softmax\'),

  ])

  resnet50_new.compile(loss="categorical_crossentropy",

  optimizer="sgd", metrics=[\'accuracy\'])

  resnet50_new.summary()

  四,训练模型

  epochs = 10

  # history = resnet50_fine_tune.fit_generator(train_generator,

  history = resnet50_new.fit_generator(train_generator,

  steps_per_epoch = train_num // batch_size,

  epochs = epochs,

  validation_data = valid_generator,

  validation_steps = valid_num // batch_size)

  五,打印模型训练曲线

  def plot_learning_curves(history, label, epcohs, min_value, max_value):

  data = {}

  data[label] = history.history[label]

  data[\'val_\'+label] = history.history[\'val_\'+label]

  pd.DataFrame(data).plot(figsize=(8, 5))

  plt.grid(True)

  plt.axis([0, epochs, min_value, max_value])

  plt.show()

  plot_learning_curves(history, \'accuracy\', epochs, 0, 1)

  plot_learning_curves(history, \'loss\', epochs, 0, 2)

  六,总结代码

  #!/usr/bin/env python3

  # -*- coding: utf-8 -*-

  import matplotlib as mpl

  import matplotlib.pyplot as plt

  import numpy as np

  import os

  import pandas as pd

  import sklearn

  import sys

  import tensorflow as tf

  import time

  from tensorflow import keras

  # 打印使用的python库的版本信息

  print(tf.__version__)

  print(sys.version_info)

  for module in mpl, np, pd, sklearn, tf, keras:

  print(module.__name__, module.__version__)

  # 1,实现tensorflow动态按需分配GPU

  from tensorflow.compat.v1 import ConfigProto

  from tensorflow.compat.v1 import InteractiveSession

  config = ConfigProto()

  config.gpu_options.allow_growth = True

  session = InteractiveSession(config=config)

  # 常量的定义

  train_dir = "./input/training/training"

  valid_dir = "./input/validation/validation"

  label_file = "./input/monkey_labels.txt"

  print(os.path.exists(train_dir))

  print(os.path.exists(valid_dir))

  print(os.path.exists(label_file))

  print(os.listdir(train_dir))

  print(os.listdir(valid_dir))

  # 查看打印出来的label值

  labels = pd.read_csv(label_file, header=0)

  print(labels)

  # 定义常量

  height = 224 # resne50的处理的图片大小

  width = 224 # resne50的处理的图片大小

  channels = 3

  batch_size = 24 # 因为处理的图片变大,batch_size变小一点 32->24

  num_classes = 10

  # 一,使用keras中ImageDataGenerator读取数据

  # 1,实例化ImageDataGenerator

  # 对于图片数据,在keras里有更高层的封装.读取数据且做数据增强 -> Generator

  train_datagen = keras.preprocessing.image.ImageDataGenerator(

  preprocessing_function = keras.applications.resnet50.preprocess_input,# 此函数是是现在keras中,而非tf.keras中,在tf中,实现数据做归一化,数据取值在-1~1之间.

  # rescale = 1./255, # 由于preprocessing_function已做了归一化,此处注释; 图像中的每个像素点都是在0~255之间,得到一个0~1之间的数

  rotation_range = 40, # 图片增强的方法,把图片随机旋转一个角度,旋转的角度就在-40~40之间

  width_shift_range = 0.2, # 做水平位移 - 增加位移鲁棒性(如果0~1之间则位移比例随机选数做位移;如果大于1,则是具体的像素大小)

  height_shift_range = 0.2, # 做垂直位移 - 增加位移鲁棒性(如果0~1之间则位移比例随机选数做位移;如果大于1,则是具体的像素大小)

  shear_range = 0.2, # 剪切强度枣庄妇科医院哪家好 http://mobile.0632dffk.com/

  zoom_range = 0.2, # 缩放强度

  horizontal_flip = True, # 是否随机做水平翻转

  fill_mode = \'nearest\', # 填充像素规则,用离其最近的像素点做填充

  )

  # 2,使用ImageDataGenerator读取图片

  # 从训练集的文件夹中读取图片

  train_generator = train_datagen.flow_from_directory(train_dir,# 图片的文件夹位置

  target_size = (height, width),# 将图片缩放到的大小

  batch_size = batch_size, # 多少张为一组

  seed = 7,#随机数种子

  shuffle = True,# 是否做混插

  class_mode = "categorical") # 控制目标值label的形式-选择onehot编码后的形式

  # 从验证集的文件夹中读取图片

  valid_datagen = keras.preprocessing.image.ImageDataGenerator(

  preprocessing_function = keras.applications.resnet50.preprocess_input)

  valid_generator = valid_datagen.flow_from_directory(valid_dir,

  target_size = (height, width),

  batch_size = batch_size,

  seed = 7,

  shuffle = False,

  class_mode = "categorical")

  # 3,查看训练家和验证集分别有多少张数据

  train_num = train_generator.samples

  valid_num = valid_generator.samples

  print(train_num, valid_num)

  # 4,如何从ImageDataGenerator中读取数据

  for i in range(2):

  x, y = train_generator.next()

  print(x.shape, y.shape)

  print(y)

  # 二,构建模型

  # 1,ResNet50中50层参数均不变

  resnet50_fine_tune = keras.models.Sequential()

  resnet50_fine_tune.add(keras.applications.ResNet50(include_top = False, # 网络结构的最后一层,resnet50有1000类,去掉最后一层

  pooling = \'avg\', #resnet50模型倒数第二层的输出是三维矩阵-卷积层的输出,做pooling或展平

  weights = \'imagenet\')) # 参数有两种imagenet和None,None为从头开始训练,imagenet为从网络下载已训练好的模型开始训练

  resnet50_fine_tune.add(keras.layers.Dense(num_classes, activation = \'softmax\')) # 因为include_top = False,所以需要自己定义最后一层

  resnet50_fine_tune.layers[0].trainable = False # 因为参数是从imagenet初始化的,所以我们可以只调整最后一层的参数

  resnet50_fine_tune.compile(loss="categorical_crossentropy",

  optimizer="sgd", metrics=[\'accuracy\']) #对于微调-finetune来说,优化器使用sgd来说更好一些

  resnet50_fine_tune.summary()

  # 2,ResNet50中后5层参数均变化

  resnet50 = keras.applications.ResNet50(include_top = False,

  pooling = \'avg\',

  weights = \'imagenet\')

  resnet50.summary()

  for layer in resnet50.layers[0:-5]:

  layer.trainable = False

  resnet50_new = keras.models.Sequential([

  resnet50,

  keras.layers.Dense(num_classes, activation = \'softmax\'),

  ])

  resnet50_new.compile(loss="categorical_crossentropy",

  optimizer="sgd", metrics=[\'accuracy\'])

  resnet50_new.summary()

  # 三,训练模型(两种模型可选择训练)

  epochs = 10

  # history = resnet50_fine_tune.fit_generator(train_generator,

  history = resnet50_new.fit_generator(train_generator,

  steps_per_epoch = train_num // batch_size,

  epochs = epochs,

  validation_data = valid_generator,

  validation_steps = valid_num // batch_size)

  # 四,打印模型训练曲线

  def plot_learning_curves(history, label, epcohs, min_value, max_value):

  data = {}

  data[label] = history.history[label]

  data[\'val_\'+label] = history.history[\'val_\'+label]

  pd.DataFrame(data).plot(figsize=(8, 5))

  plt.grid(True)

  plt.axis([0, epochs, min_value, max_value])

  plt.show()

  plot_learning_curves(history, \'accuracy\', epochs, 0, 1)

  plot_learning_curves(history, \'loss\', epochs, 0, 2)