keras 訓練 自己的圖像分類

目錄

1.構建數據集

  1.1數據增強

參數解釋:

1.2根據batch_size構建訓練集

參數解釋:

2.構建模型

2.1.不加載權重,從頭訓練

參數解釋

2.2 加載imagenet訓練好的權重,修改網絡後幾層。

3.訓練

4.測試

5.完整的代碼

5.1 train

5.2 predict



1.構建數據集

  1.1數據增強

train_datagen = ImageDataGenerator(
            rescale=1. / 255,
            shear_range=0.2,
            zoom_range=0.2,
            rotation_range=90,
            width_shift_range=0.2,
            height_shift_range=0.2,
            horizontal_flip=True
        )

參數解釋:

# featurewise_center: Boolean.對輸入的圖片每個通道減去每個通道對應均值。
# samplewise_center: Boolan.每張圖片減去樣本均值, 使得每個樣本均值爲0。
# featurewise_std_normalization(): Boolean()
# samplewise_std_normalization(): Boolean()
# zca_epsilon(): Default
# zca_whitening: Boolean.去除樣本之間的相關性
# rotation_range(): 旋轉範圍
# width_shift_range(): 水平平移範圍
# height_shift_range(): 垂直平移範圍
# shear_range(): float, 透視變換的範圍
# zoom_range(): 縮放範圍
# fill_mode: 填充模式, constant, nearest, reflect
# cval: fill_mode == 'constant'
# 的時候填充值
# horizontal_flip(): 水平反轉
# vertical_flip(): 垂直翻轉
# preprocessing_function(): user提供的處理函數
# data_format(): channels_first或者channels_last
# validation_split(): 多少數據用於驗證集

1.2根據batch_size構建訓練集

        train_generator = train_datagen.flow_from_directory(
            train_data_dir,
            target_size=(img_rows, img_cols),
            batch_size=batch_size,
            class_mode='binary')

參數解釋:

# class_mode: "categorical", "binary", "sparse"或None之一. 默認爲"categorical. 該參數決定了返回的標籤數組的形式, "categorical"會返回2D的one-hot編碼標籤,"binary"返回1D的二值標籤."sparse"返回1D的整數標籤,如果爲None則不返回任何標籤, 生成器將僅僅生成batch數據

如果是二分類class_model=binary,如果是多分類class_model=categorical

2.構建模型

2.1.不加載權重,從頭訓練

model = MobileNetV2(weights=None, classes=2, input_shape=(64,64,3))
# 定義訓練參數
# 採用隨機梯度下降法,學習率初始值0.1,動量參數爲0.9,學習率衰減值爲1e-6,確定使用Nesterov動量
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
# 配置模型學習過程,目標函數爲categorical_crossentropy:亦稱作多類的對數損失,注意使用該目標函數時,需要將標籤轉化爲形如(nb_samples, nb_classes)的二值序列
model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])

參數解釋

optimizer:優化器,Adam,rmsprop(root mean square prop)、adagrad等優化器,

loss:計算損失,這裏用的是交叉熵損失,binary_crossentropy(二分類)categorical_crossentropy(多分類)

metrics: 列表,包含評估模型在訓練和測試時的性能的指標,典型用法是metrics=[‘accuracy’]。

2.2 加載imagenet訓練好的權重,修改網絡後幾層。

        Inp = Input((img_rows, img_cols, color))
        base_model = VGG19(weights='imagenet', include_top=False, pooling=None, input_shape=(img_rows, img_cols, color),
                           classes=nb_classes)

        top_model = Sequential()
        top_model.add(Flatten(input_shape=base_model.output_shape[1:]))  # model.output_shape[1:])
        top_model.add(Dense(256, activation='relu'))
        top_model.add(Dropout(0.8))
        top_model.add(Dense(nb_classes, activation='sigmoid'))

        # 訓練模型
        model = Model(inputs=base_model.input, outputs=top_model(base_model.output))

        # 凍結base_model所有層,這樣就可以正確獲得bottleneck特徵
        for layer in base_model.layers:
            layer.trainable = False

        sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True)
        model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

base_model 就是把vgg19全連接層去掉後用於提取特徵的網絡層,採用imagenet訓練過的權重,

top_model 就是把提取的特徵,用於分類,自己構建的分類網絡

凍結 base_model層,只訓練我們的分類網絡

記住,凍結一定要放在model後面 和compile前面

3.訓練

    hist = model.fit_generator(
        train_generator,
        validation_data=validation_generator,
        steps_per_epoch=count1 // batch,
        validation_steps=count2 // batch,
        epochs=epochs,
        callbacks=[earlystop])

    df = pd.DataFrame.from_dict(hist.history)
    df.to_csv('model/hist.csv', encoding='utf-8', index=False)

參照批次訓練,減少內存的使用

4.測試

from keras.preprocessing import image
import numpy as np
import os
from keras.applications.mobilenetv2 import decode_predictions, preprocess_input
from keras.applications.mobilenetv2 import MobileNetV2
from keras.layers import Conv2D, Reshape, Activation,Dropout
from keras.models import Model
# 預測測試
import time
path = "C:\\classi\\validation\\A\\"
classes=['error','ok']
# model = MobileNetV2((32, 32, 3), include_top=False, alpha=1.0, classes=2)
model = MobileNetV2(input_shape=(64,64,3),weights=None,classes=2)
model.load_weights('best_MobileNetV2_2019.7.23.h5')
print(model.summary())
for i in os.listdir(path):
    img_path=path+i
    img = image.load_img(img_path, target_size=(64, 64))
    # mobilenetv2
    t0 = time.time()
    x = image.img_to_array(img) / 255
    x = np.expand_dims(x, axis=0)
    preds = model.predict(x)

    t1 = time.time()
    # print('mobilenetv2 Predicted:', decode_predictions(preds, top=1))
    print('class name=%s' %(classes[int(np.argmax(preds,axis=1))])+'||probe= %.3f '%(np.max(preds)))
    print('times:', t1 - t0)

5.完整的代碼

5.1 train

# -*- coding: utf-8 -*-
# @Time    : 2019/11/5 11:13
# @Author  : Don
# @File    : train_inceptionv3.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
import os
from keras.utils import plot_model
from keras.applications.resnet50 import ResNet50
from keras.applications.vgg19 import VGG19
from keras.applications.inception_v3 import InceptionV3
from keras.layers import Dense, Flatten, GlobalAveragePooling2D, Input, regularizers, BatchNormalization, Dropout
from keras.models import Model, load_model, Sequential
from keras.optimizers import SGD
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
from keras.regularizers import l2
from keras.applications.mobilenetv2 import MobileNetV2

class PowerTransferMode:
    # 數據準備
    def DataGen(self, dir_path, img_row, img_col, batch_size, is_train):
        if is_train:
            datagen = ImageDataGenerator(rescale=1. / 255,
                                         zoom_range=0.25, rotation_range=15.,
                                         channel_shift_range=25., width_shift_range=0.02, height_shift_range=0.02,
                                         horizontal_flip=True, fill_mode='constant')
        else:
            datagen = ImageDataGenerator(rescale=1. / 255)

        generator = datagen.flow_from_directory(
            dir_path, target_size=(img_row, img_col),
            batch_size=batch_size,
            # class_mode='binary',
            shuffle=is_train)

        return generator

    # ResNet模型
    def ResNet50_model(self, lr=0.005, decay=1e-6, momentum=0.9, nb_classes=2, img_rows=197, img_cols=197, RGB=True,
                       is_plot_model=False):
        color = 3 if RGB else 1

        Inp = Input((img_rows, img_cols, color))
        print(Inp)
        base_model = ResNet50(weights='imagenet', include_top=False,
                              input_shape=(img_rows, img_cols, color),
                              classes=nb_classes)

        x = base_model(Inp)
        x = GlobalAveragePooling2D(name='average_pool')(x)
        # x = Flatten(name='flatten')(x)
        x = Dense(2048, activation='relu', kernel_regularizer=regularizers.l2(0.0001), )(x)
        x = BatchNormalization()(x)
        x = Dense(1024, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x)
        x = BatchNormalization(name='bn_fc_01')(x)
        predictions = Dense(nb_classes, activation='softmax')(x)

        # 訓練模型
        model = Model(inputs=Inp, outputs=predictions)

        # 凍結base_model所有層,這樣就可以正確獲得bottleneck特徵
        for layer in base_model.layers:
            layer.trainable = False

        sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True)
        model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

        # 繪製模型
        if is_plot_model:
            plot_model(model, to_file='resnet50_model.png', show_shapes=True)

        return model

    # VGG模型
    def VGG19_model(self, lr=0.005, decay=1e-6, momentum=0.9, nb_classes=2, img_rows=197, img_cols=197, RGB=True,
                    is_plot_model=False):
        color = 3 if RGB else 1
        Inp = Input((img_rows, img_cols, color))
        base_model = VGG19(weights='imagenet', include_top=False, pooling=None, input_shape=(img_rows, img_cols, color),
                           classes=nb_classes)

        top_model = Sequential()
        top_model.add(Flatten(input_shape=base_model.output_shape[1:]))  # model.output_shape[1:])
        top_model.add(Dense(256, activation='relu'))
        top_model.add(Dropout(0.8))
        top_model.add(Dense(nb_classes, activation='sigmoid'))

        # 訓練模型
        model = Model(inputs=base_model.input, outputs=top_model(base_model.output))

        # 凍結base_model所有層,這樣就可以正確獲得bottleneck特徵
        for layer in base_model.layers:
            layer.trainable = False

        sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True)
        model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

        # 繪圖
        if is_plot_model:
            plot_model(model, to_file='vgg19_model.png', show_shapes=True)

        return model

    # InceptionV3模型
    def InceptionV3_model(self, lr=0.005, decay=1e-6, momentum=0.9, nb_classes=2, img_rows=197, img_cols=197,
                          RGB=True,
                          is_plot_model=False):
        color = 3 if RGB else 1

        Inp = Input((img_rows, img_cols, color))
        print(Inp)
        base_model = InceptionV3(weights='imagenet', include_top=False,
                                 input_shape=(img_rows, img_cols, color),
                                 classes=nb_classes)

        x = base_model(Inp)
        x = GlobalAveragePooling2D(name='average_pool')(x)
        # x = Flatten(name='flatten')(x)
        x = Dense(2048, activation='relu', kernel_regularizer=regularizers.l2(0.0001), )(x)
        x = BatchNormalization()(x)
        x = Dense(1024, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x)
        x = BatchNormalization(name='bn_fc_01')(x)
        predictions = Dense(nb_classes, activation='softmax')(x)

        # 訓練模型
        model = Model(inputs=Inp, outputs=predictions)

        # 凍結base_model所有層,這樣就可以正確獲得bottleneck特徵
        for layer in base_model.layers:
            layer.trainable = False

        sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True)
        model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

        # 繪圖
        # if is_plot_model:
        # plot_model(model, to_file='inception_v3_model.png', show_shapes=True)

        return model

    # MobileNetv2模型
    def MobileNetv2_model(self, lr=0.005, decay=1e-6, momentum=0.9, nb_classes=2, img_rows=197, img_cols=197,
                          RGB=True,
                          is_plot_model=False):
        color = 3 if RGB else 1

        Inp = Input((img_rows, img_cols, color))
        print(Inp)
        base_model = MobileNetV2(weights='imagenet', include_top=False,
                                 input_shape=(img_rows, img_cols, color),
                                 classes=nb_classes)

        x = base_model(Inp)
        x = GlobalAveragePooling2D(name='average_pool')(x)
        # x = Flatten(name='flatten')(x)
        x = Dense(2048, activation='relu', kernel_regularizer=regularizers.l2(0.0001), )(x)
        x = BatchNormalization()(x)
        x = Dense(1024, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x)
        x = BatchNormalization(name='bn_fc_01')(x)
        predictions = Dense(nb_classes, activation='softmax')(x)

        # 訓練模型
        model = Model(inputs=Inp, outputs=predictions)

        # 凍結base_model所有層,這樣就可以正確獲得bottleneck特徵
        for layer in base_model.layers:
            layer.trainable = False

        sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True)
        model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

        # 繪圖
        if is_plot_model:
            plot_model(model, to_file='Mobilenet_v2_model.png', show_shapes=True)

        return model

    # 訓練模型
    def train_model(self, model, epochs, train_generator, steps_per_epoch, validation_generator, validation_steps,
                    model_url, is_load_model=False):
        # 載入模型
        if is_load_model and os.path.exists(model_url):
            model = load_model(model_url)

        history_ft = model.fit_generator(
            train_generator,
            steps_per_epoch=steps_per_epoch,
            epochs=epochs,
            validation_data=validation_generator,
            validation_steps=validation_steps)
        # 模型保存
        model.save(model_url, overwrite=True)
        return history_ft

    # 畫圖
    def plot_training(self, 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, 'b-')
        plt.plot(epochs, val_acc, 'r')
        plt.title('Training and validation accuracy')
        plt.figure()
        plt.plot(epochs, loss, 'b-')
        plt.plot(epochs, val_loss, 'r-')
        plt.title('Training and validation loss')
        plt.show()


if __name__ == '__main__':
    image_size = 75
    batch_size = 32

    transfer = PowerTransferMode()

    # 得到數據
    train_generator = transfer.DataGen('C:\\classi\\train', image_size, image_size, batch_size, True)
    validation_generator = transfer.DataGen('C:\\classi\\validation', image_size, image_size, batch_size, False)

    # VGG19
    model = transfer.VGG19_model(nb_classes=2, img_rows=image_size, img_cols=image_size, is_plot_model=False)
    history_ft = transfer.train_model(model, 100, train_generator, 50, validation_generator, 20,
                                      'vgg19_model_weights.h5', is_load_model=False)

    # ResNet50
    # model = transfer.ResNet50_model(nb_classes=2, img_rows=image_size, img_cols=image_size, is_plot_model=False)
    # history_ft = transfer.train_model(model, 100, train_generator, 50, validation_generator, 20,
    #                                   'resnet50_model_weights.h5', is_load_model=False)

    # InceptionV3
    # model = transfer.InceptionV3_model(nb_classes=2, img_rows=image_size, img_cols=image_size, is_plot_model=True)
    # history_ft = transfer.train_model(model, 100, train_generator, 50, validation_generator, 20,
    #                                   'inception_v3_model_weights.h5', is_load_model=False)

    # MobileNetv2
    # model = transfer.MobileNetv2_model(nb_classes=2, img_rows=image_size, img_cols=image_size, is_plot_model=True)
    # history_ft = transfer.train_model(model, 100, train_generator, 50, validation_generator, 20,
    #                                   'mobileNetv2_model_weights.h5', is_load_model=False)

    transfer.plot_training(history_ft)

5.2 predict

# -*- coding: utf-8 -*-
# @Time    : 2019/10/30 14:25
# @Author  : Don
# @File    : predict.py
# @Software: PyCharm
from keras.preprocessing import image
import numpy as np
import os
from keras.applications.mobilenetv2 import decode_predictions, preprocess_input
from keras.applications.mobilenetv2 import MobileNetV2
from keras.layers import Conv2D, Reshape, Activation,Dropout
from keras.models import Model
# 預測測試
import time
path = "C:\\classi\\validation\\A\\"
classes=['error','ok']
# model = MobileNetV2((32, 32, 3), include_top=False, alpha=1.0, classes=2)
model = MobileNetV2(input_shape=(64,64,3),weights=None,classes=2)
model.load_weights('best_MobileNetV2_2019.7.23.h5')
print(model.summary())
for i in os.listdir(path):
    img_path=path+i
    img = image.load_img(img_path, target_size=(64, 64))
    # mobilenetv2
    t0 = time.time()
    x = image.img_to_array(img) / 255
    x = np.expand_dims(x, axis=0)
    preds = model.predict(x)

    t1 = time.time()
    # print('mobilenetv2 Predicted:', decode_predictions(preds, top=1))
    print('class name=%s' %(classes[int(np.argmax(preds,axis=1))])+'||probe= %.3f '%(np.max(preds)))
    print('times:', t1 - t0)



參考:https://blog.csdn.net/pengdali/article/details/79050662

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章