Keras使用心得

三大步骤 模型+策略+算法

一般来说需要导入的包

# 其他包
import os
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# 一般性导入的包
import tensorflow as tf
import keras
from keras import layers, models, optimizers, metrics, regularizers
from keras.callbacks import ModelCheckpoint
from keras.models import load_model
from keras.utils.vis_utils import plot_model

# 图像处理相关包
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array

# 导入预训练模型的包
from keras.applications import VGG16, ResNet50, MobileNet

1. model.Squential()创建model(模型)

model = models.Sequential()
## 输入层
# Dense输入层
model.add(layers.Dense(256, activation='relu',input_shape=(784,))) 
# 256是输出到的下一层隐藏层的单元数,784是输入的维数28x28

# conv输入层
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding = 'same',input_shape=(48,48, 3)))
# 32是输出到的下一层卷积层的feature maps数(channel数),(48,48,3)是输入的维数(48,48)的像素,channel为3

## 隐藏层
# Dense隐藏层标准步骤
model.add(layers.Dense(512, activation='relu'))
model.add(layers.normalization.BatchNormalization())
model.add(layers.Dropout(0.25))
........

# conv隐藏层标准步骤
model.add(layers.Conv2D(64, (3, 3),activation='relu',padding = 'same'))
model.add(layers.normalization.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Dropout(0.25))

## 输出层
# Dense输出层
model.add(layers.Flatten()) # 一定要先展开

model.add(layers.Dense(512,activation='relu')) # 再经过一个全连接层
model.add(layers.normalization.BatchNormalization())
model.add(layers.Dropout(0.25))
model.add(layers.Dense(7, activation='softmax'))


查看搭建好的模型架构

# 文字形式的架构
model.summary()
# 图片形式的架构
plot_model(model, show_shapes=True, show_layer_names=True)

2. model.compile()编译损失函数和优化器(策略和算法)

 model.compile(loss=...
    			optimizer=...
        		metrics=...# loss 表示计算损失函数时的指标,optimizer表示优化的策略,metrics表示评估的指标

# 回归
model.compile(loss='mse',
              optimizer=optimizers.RMSprop(lr=1e-5),
              metrics=['mse']) # metrics可以和loss相同,也可以和loss不同,如loss='mse',metrics=['mae'],metrics=[metrics.RootMeanSquaredError()]

# 二分类
model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-5),
              metrics=['acc'])
# 多分类
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.Adam(lr=1e-3),
              metrics=['acc'])

3. 设置记录最好的model(此步也可以省略)

此步骤要在真正开始训练模型之前

filepath = "文件要保存的路径+名字.h5"  # h5是固定的保存格式 如"model/best_no_aug_vgg16.h5"
checkpoint = ModelCheckpoint(filepath, monitor='val_acc',verbose=1, mode='max',save_best_only=True)
# ModelCheckpoint中monitor是监考的指标, mode是策略,verbose=1表示显示详细信息,verbose=2显示简要信息
# 如果是回归问题,monitor='val_loss'
# 如果指标是均方误差的平方根,monitor='val_root_mean_squared_error'

4. 真正开始训练模型

执行fit指令后才开始真正开始训练模型

注意:执行完fit指令后,会保存最终的参数在model中

此时如果再次执行fit指令并不会重新训练该模型,而是在刚刚训练完毕的基础上再训练

按照下面的例子说,如果执行了100epochs后再执行一遍,并不会覆盖原来的参数,会在原来训练好的参数的基础上再次训练模型,也就是说两次执行下列命令后相当于跑了200epochs

一般训练的时间会很长,这个机制的好处是可以在训练一个小的epochs可视化结果后,继续训练,可以达到同样大epochs的效果

如果要重新训练模型必须要从第1步创建模型开始重新训练模型

history = model.fit(X_train,
                    y_train,
                    epochs= 100,
                    batch_size= 128,
                    validation_data=(X_val, y_val)
                    callbacks=[checkpoint]) # 第三步创建的checkpoint外要加一个list[]
# 需要设定训练集特征以及标签,训练的epochs,每轮epchos中每一小批量的批量大小为多少,最后还要加上验证集的特征以及标签

# 运行完成后的loss和acc参数都保存进入了history的history里
train_loss = history.history['loss']
val_loss = history.history['val_loss']
train_acc = history.history['acc']
val_acc = history.history['val_acc']

5. 可视化模型训练的表现

下面两个函数是模型训练过程中的train/val set中,分别对loss和acc的对比图

def plot_loss(train_loss,val_loss,nepochs):
    plt.clf()
    plt.figure(figsize=(16,6))
    plt.plot(range(1,nepochs+1), train_loss, label='train loss',color="blue")
    plt.plot(range(1,nepochs+1), val_loss, label='validation loss',color="red")
    
    plt.title('min(validation loss) = ' + str(round(min(val_loss),3)),fontsize=16)
    plt.axhline(min(val_loss), linestyle='--', color='.5')
    plt.xlabel('Epochs',fontsize=16)
    plt.ylabel('Loss',fontsize=16)
    plt.grid(True)
    plt.legend(loc = 'upper right',fontsize=16)

    plt.show()
    
def plot_acc(train_acc,val_acc,nepochs):
    plt.clf()
    plt.figure(figsize=(16,6))
    plt.plot(range(1,nepochs+1), train_acc, label='train accuracy',color="blue")
    plt.plot(range(1,nepochs+1), val_acc, label='validation accuracy',color="red")

    plt.title('max(validation accuracy) = ' + str(round(max(val_acc),3)),fontsize=16)
    plt.axhline(max(val_acc), linestyle='--', color='.5')
    plt.xlabel('Epochs',fontsize=16) 
    plt.ylabel('Accuracy',fontsize=16)
    plt.grid(True)
    plt.legend(loc = 'lower right',fontsize=16)

    plt.show()
    
train_loss = history.history['loss']
val_loss = history.history['val_loss']
plot_loss(train_loss,val_loss,len(train_loss))

train_acc = history.history['acc']
val_acc = history.history['val_acc']
plot_acc(train_acc,val_acc,len(train_acc))

6 预测结果

可以拿训练好的模型来预测其他类似数据来源的结果

y_hat = model.predict(X_val)
# 回归问题
# 回归问题会返回一连串的预测值,数量和样本数相同,y_hat的维度是(m,),m表示样本数

# 分类问题
# 分类问题会返回概率值, y_hat的维度是(m,n),m表示样本数,n表示分类数,二分类中n=2
# 如果是二分类即binary_crossentropy,返回2个概率值,而不是0,1
# 如果是多分类问题categorical_crossentropy,返回n个概率值,数量与softmax的输出维度n相同,而不是0,1,2....

y_hat = np.argmax(y_hat, axis = 1)
# 分类问题还要进行一步转换,返回每一行的最大值的索引,最终变为(m,)维,且值为0,1,2....

7. 保存最终模型和复调用模型

# 保存最终模型
model.save('文件要保存的路径+名字.h5') # h5是固定的保存格式 如"model/final_model.h5"

# 调用模型
# 用途1:可以下次关闭后重新打开加载模型,并预测模型 model.predict()
# 用途2:可以加载不同的模型并对其在原来训练过的基础上,继续训练 model.fit()
model = load_model('test_model.h5')

图片处理(ImageDataGenerator)

ImageDataGenerator是专门用于流式处理图片的方法,它不用先把所有图片导入内存,而是通过类似sparkstraming的流式批量导入图片并处理,这样可以减少内存的利用,加快速度

下面以图片分类为例子

1. 导入图片

注意使用ImageDataGenerator的前提是创建两个文件夹,train文件夹和validation文件夹

train/validation中各个种类的图片必须打包在对应的各个子文件夹中,如有两类cat和dog,cat的图片必须在cat的子文件夹中,dog的图片必须在dog的子文件夹中

train_dir = 'images//train/'
validation_dir = 'images//validation/'

os.listdir(train_dir)

2. 展示图片

plt.figure(0, figsize=(48,48))
cpt = 0

for expression in os.listdir(train_dir):
    for i in range(1,6):
        cpt = cpt + 1
        sp=plt.subplot(7,5,cpt)
        sp.axis('Off')
        img_path = train_dir + expression + "/" +os.listdir(train_dir + expression)[i]
        img = load_img( img_path, target_size=(48,48))
        plt.imshow(img, cmap="gray")
        plt.title(expression,fontsize=40)


plt.show()

3. 生成图片流

train_datagen = ImageDataGenerator(rescale=1./255) # 要对像素归一化
validation_datagen = ImageDataGenerator(rescale=1./255)

batch_size = 128
train_generator = train_datagen.flow_from_directory (train_dir,   
                                                     target_size=(48, 48),  
                                                     batch_size=batch_size,
                                                     shuffle=True, # shuffle参数默认是true
                                                     class_mode='categorical',
                                                     color_mode="rgb")  
										# color_mode="rgb"是表示3通道彩色图,"grayscale"表示单通道灰度图


validation_generator = validation_datagen.flow_from_directory(validation_dir,  
                                                              target_size=(48,48), 
                                                              batch_size=batch_size,
                                                              shuffle=True, 
                                                              # 也有人将测试集的shuffle设为false
                                                              class_mode='categorical',
                                                              color_mode="rgb")
# batch_size代表每一次生成的图片流中图片的数量,shuffle=True表示后面每个epochs后都会打乱数据集
# 注意validation数据集的batch_size可以和train数据集中的不同,但一般方便起见都可以设置为相同的batch_size大小

数据增强 DataAugment

在生成数据前,为了防止过拟合和增强模型对大变化性数据的鲁棒性,经常使用数据增强来微调训练集中的图片增加一些变化

train_datagen = ImageDataGenerator(
      rescale=1./255,
      rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

# 注意,不能增强验证数据
validation_datagen = ImageDataGenerator(rescale=1./255)

# 后面和前面一致
batch_size = 128
train_generator =  .....
validation_generator = ...

4 训练图片流模型

fit_generator与fit相比,可以节省内存,fit会将所有的数据一次性读进来,fit_generator需要使用对应的data_generator.
fit_generator通过定义validation_data和validation_steps两个参数来设置验证集

图片流的产生是无穷无尽的,因为遍历抽取完了所有的图片后,图片流会重新再对数据集进行遍历抽取,每次抽取的图片流的数量即位第三部中设置的batch_size

其实本质上流式模型和一般模型的原理都是相同的,都是尽量在每一个epoch中遍历一遍所有的数据

如何在一次epoch中保证遍历所有的数据需要我们自己控制

steps_per_epoch=train_generator.n//train_generator.batch_size

validation_steps=validation_generator.n//validation_generator.batch_size

steps_per_epoch表示每次epoch抽取训练集中图片流的次数,同理validation_steps表示每次epoch抽取测试集中图片流的次数

train_generator.n参数是保存在train_generator中所有训练集的样本数,train_generator.batch_size则是批量大小

同理validation_generator.n和validation_generator.batch_size

因为steps_per_epoch和validation_steps都是要手动设置的,所以按照上面的公式可以保证所有的数据在一个epoch中都能被遍历一次而且没有重复

history = model.fit_generator(
      train_generator,
      steps_per_epoch=train_generator.n//train_generator.batch_size,
      epochs=100,
      validation_data=validation_generator,
      validation_steps=validation_generator.n//validation_generator.batch_size,
      verbose=2,
      callbacks=[checkpoint])

总结:验证会进行在当前epoch结束后进行,

validation batch size没必要和train batch相等,但为了方便起见一般设为相等

validation_steps设置了抽取图片流的次数(batch数量),

validation_steps (相当于一共抽取的batch数, 为了不重复,应保证<=TotalvalidationSamples / ValidationBatchSize)

validation batch size=64,validation_steps=100,会从validation data中取6400个数据用于验证
(如果一次step抽取后validation data set剩下的data足够下一次step,会继续从剩下的data set中选取, 如果不够会重新循环).

建议使用整个验证集用于验证,否则每次验证的结果没有太大可比性(使用的验证数据不同)

5 可视化模型表现和预测结果以及保存

这一步和上面的5,6,7 步中一致,没有区别

不过需要注意在预测时:

上面的一般性是有测试集的特征的,即

yhat = model.predict(X_val)

而下面的直接对val的图片流进行预测,不用提取特征出来, 返回的直接是回归预测值/类别的概率

yhat = model.predict(validation_generator)

注意如果要将yhat和真正的标签对比时,一定要将validation_generator中的shuffle设为false

# set the 'shuffle' of the validation_generator to be false
validation_generator = validation_datagen.flow_from_directory(validation_dir,  
                                                              target_size=(48,48), 
                                                              batch_size=batch_size,
                                                              class_mode='categorical',
                                                              shuffle = False, # 一定要设为false
                                                              color_mode="rgb")

pre = model.predict(validation_generator)
yhat = np.argmax(pre, axis=1)
y_test = validation_generator.classes
acc = np.sum(y_pred == y_test)/validation_generator.n  # 准确度

ImageDataGenerator的其他一些重要属性或函数

  1. train_generator.n参数是保存在train_generator中训练集的样本总数

  2. train_generator.batch_size则是批量大小

    同理validation_generator.nvalidation_generator.batch_size是对应测试集

  3. **validation_generator.next()**返回的是下一批量即validation batch size数量的样本,返回的是两个数组(样本的特征以及对应的标签)用法:X,y = validation_generator.next()

    同理train_generator.next()

  4. train_generator.classes返回的是训练集的所有样本的类别数值的数组,如array[0,0,0…6,6] 一般顺序是按照类别值来的

    validation_generator.classes返回的是测试集的所有样本的类别数值的数组

  5. train_generator.class_indicesvalidation_generator.class_indices(这两者返回的一般都相同)返回的是样本的类别标签

    返回的是一个字典,是以键值对的形式,key是类别名(即子文件名),而value则是其对应的index即类别值

    如具有7个类别标签的样本集,image-20210805221714879

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值