【keras实战】用DenseNet实现五种花的分类

 

前言

        本次实战是应用keras已经封装好的application模型DenseNet 来做分类,提供代码以供参考。代码除了需要更改路径和分类数(我的数据集是5类)外,应该不需要做其它改动可以直接运行。本文的代码基本都是拿别人的代码拼拼凑凑修修剪剪得到的,没什么原创性,所以不会上传github。(给自己的懒惰找了个正当的理由~)

参考

           训练和测试代码   

            keras系列︱迁移学习:利用InceptionV3进行fine-tuning及预测、完美案例(五)

            保存模型和tensorboard可视化

            keras系列︱Sequential与Model模型、keras基本结构功能(一)

            denseNet源代码和各个模型的比较可参考github上keras-team的keras-applications项目:

            Reference implementations of popular deep learning models

            优化算法参数设置,添加层的设置等

            论文:Densely Connected Convolutional Networks     

一、准备工作

       在进行具体的分类任务之前,我们先来检查一下工作环境

      1、已经安装好的keras是否有DenseNet这个模型?

       打开终端(Windows系统下即cmd,Ubuntu可用快捷键Ctrl+Alt+T),启动python环境,输入下图的指令可以查看keras.applications的文档。从我红圈圈出来的部分可以看到densenet这个包是存在的。如果不存在请更新keras版本

【keras实战】用DenseNet实现五种花的分类_第1张图片

          2、打印DenseNet模型,对模型架构有个大概的认知。

                获取模型信息的代码如下:

#--coding:utf-8--
#获得模型信息的代码
from keras.applications.densenet import DenseNet201,preprocess_input
from keras.layers import Dense, GlobalAveragePooling2D
from keras.models import Model

#base_model = DenseNet(weights='imagenet', include_top=False)
base_model = DenseNet201(include_top=False)

x = base_model.output
x = GlobalAveragePooling2D()(x) 
predictions = Dense(5, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)

model.summary()
print('the number of layers in this model:'+str(len(model.layers)))

        输出结果很长,最后部分截图:

【keras实战】用DenseNet实现五种花的分类_第2张图片

        可以看到这个模型densenet201有709layer.

二、准备数据集

       采用的数据集同【keras实战】用Inceptionv3实现五种花的分类,关于数据集如何划分的问题也请参考这篇博文。

三、训练

系统:Ubuntu 16.04 LTS(Windows系统问题也不大)

GPU:GeForce GTX 1080 Ti

代码:

最近更新特别说明:我把tensorboard可视化的代码改成了plt绘制函数,但是训练过程的那个图还是之前tensorboard的图。

# --coding:utf-8--
import os
import sys
import glob
import matplotlib.pyplot as plt

from keras import __version__
from keras.applications.densenet import DenseNet201,preprocess_input

from keras.models import Model
from keras.layers import Dense, GlobalAveragePooling2D
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import SGD
from keras.callbacks import ModelCheckpoint


def get_nb_files(directory):
  """Get number of files by searching directory recursively"""
  if not os.path.exists(directory):
    return 0
  cnt = 0
  for r, dirs, files in os.walk(directory):
    for dr in dirs:
      cnt += len(glob.glob(os.path.join(r, dr + "/*")))
  return cnt


# 数据准备
IM_WIDTH, IM_HEIGHT = 224, 224 #densenet指定的图片尺寸



train_dir = '../dataset_flower2/train'  # 训练集数据路径
val_dir = '../dataset_flower2/validate' # 验证集数据
nb_classes= 5
nb_epoch = 30
batch_size = 32

nb_train_samples = get_nb_files(train_dir)      # 训练样本个数
nb_classes = len(glob.glob(train_dir + "/*"))  # 分类数
nb_val_samples = get_nb_files(val_dir)       #验证集样本个数
nb_epoch = int(nb_epoch)                # epoch数量
batch_size = int(batch_size)           

# 图片生成器
train_datagen =  ImageDataGenerator(
  preprocessing_function=preprocess_input,
  rotation_range=30,
  width_shift_range=0.2,
  height_shift_range=0.2,
  shear_range=0.2,
  zoom_range=0.2,
  horizontal_flip=True
)
test_datagen = ImageDataGenerator(
  preprocessing_function=preprocess_input,
  rotation_range=30,
  width_shift_range=0.2,
  height_shift_range=0.2,
  shear_range=0.2,
  zoom_range=0.2,
  horizontal_flip=True
)

# 训练数据与测试数据
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(IM_WIDTH, IM_HEIGHT),
batch_size=batch_size,class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
val_dir,
target_size=(IM_WIDTH, IM_HEIGHT),
batch_size=batch_size,class_mode='categorical')

# 添加新层
def add_new_last_layer(base_model, nb_classes):
  """
  添加最后的层
  输入
  base_model和分类数量
  输出
  新的keras的model
  """
  x = base_model.output
  x = GlobalAveragePooling2D()(x)
  predictions = Dense(nb_classes, activation='softmax')(x) #new softmax layer
  model = Model(input=base_model.input, output=predictions)
  return model


#搭建模型
model = DenseNet201(include_top=False)
model = add_new_last_layer(model, nb_classes)
#model.load_weights('../model/checkpoint-02e-val_acc_0.82.hdf5')  第二次训练可以接着第一次训练得到的模型接着训练
model.compile(optimizer=SGD(lr=0.001, momentum=0.9,decay=0.0001,nesterov=True), loss='categorical_crossentropy', metrics=['accuracy'])


#更好地保存模型 Save the model after every epoch.
output_model_file = '/home/pandafish/AnacondaProjects/DenseNet/model/checkpoint-{epoch:02d}e-val_acc_{val_acc:.2f}.hdf5'
#keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
checkpoint = ModelCheckpoint(output_model_file, monitor='val_acc', verbose=1, save_best_only=True)




#开始训练
history_ft = model.fit_generator(
train_generator,
samples_per_epoch=nb_train_samples,
nb_epoch=nb_epoch,
callbacks=[checkpoint],
validation_data=validation_generator,
nb_val_samples=nb_val_samples)

def plot_training(history):
  acc = history.history['acc']
  val_acc = history.history['val_acc']
  loss = history.history['loss']
  val_loss = history.history['val_loss']
  epochs = range(len(acc))
  plt.plot(epochs, acc, 'r-')
  plt.plot(epochs, val_acc, 'b')
  plt.title('Training and validation accuracy')
  plt.figure()
  plt.plot(epochs, loss, 'r-')
  plt.plot(epochs, val_loss, 'b-')
  plt.title('Training and validation loss')
  plt.show()

# 训练的acc_loss图
plot_training(history_ft)

tensorboar 可视化训练显示结果(深色线是曲线拟合的结果,浅色线是实际曲线):

【keras实战】用DenseNet实现五种花的分类_第3张图片【keras实战】用DenseNet实现五种花的分类_第4张图片

 

【keras实战】用DenseNet实现五种花的分类_第5张图片【keras实战】用DenseNet实现五种花的分类_第6张图片

   训练时我迭代到第12个epoch就停了,事实上从第4个epoch开始验证集的准确率就开始不提升了,之后就过拟合了……

四、测试

# --coding:utf-8--
# 定义层
import sys
import argparse
import numpy as np
from PIL import Image
from io import BytesIO
import matplotlib.pyplot as plt

from keras.preprocessing import image
from keras.models import load_model
from keras.applications.densenet import preprocess_input

target_size = (224, 224) 

# 预测函数
# 输入:model,图片,目标尺寸
# 输出:预测predict
def predict(model, img, target_size):
  """Run model prediction on image
  Args:
    model: keras model
    img: PIL format image
    target_size: (w,h) tuple
  Returns:
    list of predicted labels and their probabilities
  """
  if img.size != target_size:
    img = img.resize(target_size)

  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)
  x = preprocess_input(x)
  preds = model.predict(x)
  return preds[0]

# 画图函数

labels = ("daisy", "dandelion","roses","sunflowers","tulips")
def plot_preds(image, preds,labels):
  """Displays image and the top-n predicted probabilities in a bar graph
  Args:
    image: PIL image
    preds: list of predicted labels and their probabilities
  """
  plt.imshow(image)
  plt.axis('off')
  plt.figure()
  plt.barh([0, 1,2,3,4], preds, alpha=0.5)
  plt.yticks([0, 1,2,3,4], labels)
  plt.xlabel('Probability')
  plt.xlim(0,1.01)
  plt.tight_layout()
  plt.show()

# 载入模型
model = load_model('../model/checkpoint-08e-val_acc_0.96.hdf5')

# 本地图片进行预测
img = Image.open('rose.jpg')
preds = predict(model, img, target_size)
plot_preds(img, preds,labels)

 

测试结果:

【keras实战】用DenseNet实现五种花的分类_第7张图片

【keras实战】用DenseNet实现五种花的分类_第8张图片

可能遇到的问题

       1、 运行程序时报错No model named densenet

              可能是keras版本过低导致。更新keras版本即可。

              在终端输入指令:pip install --upgrade keras

      2、keras版本更新后可能会出现keras版本和tensorflow版本不兼容的问题,具体表现形式为说你的参数不符合要求,找不到目标之类(不记得了,反正莫名其妙的错误大多数都是这类原因),我的解决方法根据报错信息手动修改tensorflow底层代码。

    

 

 

 

 

 

 

 

你可能感兴趣的:(Kera)