Keras搭建VGG搭建ResNet識別MNIST識別CIFAR10例程

keras的兩種編程方式

加載model模塊的sequential類的順序模型,特點是add,示例如下

"""
只是樣例,跑不通的
"""
import keras
from keras.layers import Dense,Conv2D
from keras.models import Sequential
import keras.optimizers as optimizers
import keras.losses as losses

model = Sequential()
model.add(Conv2D(32,(3,3),activation='relu',input_dim =100))
model.add(Dense(units =64,activation ='relu'))
model.add(Dense(units = 32,activation ='softmax'))
SGD = optimizers.SGD(lr =0.01,momentum=0.9,nesterov =True)
model.compile(loss =losses.categorical_crossentropy,optimizer = SGD,metrics = {'accuracy'})
model.fit(x_train,y_train,epoch = 5,batch_size=16)
loss_and_metrics = model.evaluate(x_test,y_test,batch_size = 16)
classes = model.predict(x,batch_size=1)

使用Model的嵌套模型也是很流行的,特點是每條語句有都加一個(x),x表輸出的特徵圖層

import keras
from keras.layers import Conv2D,MaxPooling2D,Dense,Flatten,Dropout
import keras.optimizers as optimizers
from keras.models import Model

inputs = Input(shape=(100, 100, 3))
x = Conv2D(32,(3,3),activation = 'relu')(inputs)
x = MaxPooling2D(pool_size= (2,2))(x)
x = Conv2D(32,(3,3),activation ='relu')(x)
x = MaxPooling2D(pool_size = (2,2))(x)

x = Flatten()(x)
x = Dropout(0.5)(x)
x = Dense(256,activation='relu')(x)
out = Dense(10,activation = 'softmax')(x)

model = Model(inputs = [inputs],outputs =[out])
SGD = optimizers.SGD(lr =0.001,decay = 1e-6,momentun = 0.9,nestervo = True)
model.compile(loss = 'categorical_crossentropy',optimizer= SGD,metrics = {'accuracy'})
model.fit(x_train,y_train,epoch = 5,batch_size=16)

loss_and_metrics = model.evaluate(x_test,y_test,batch_size = 16)
classes = model.predict(x,batch_size=1)

使用keras搭建神經網絡識別三類數據練習

github地址

環境說明

  1. keras2.0
  2. 後端tensorflow-gpu版1.6
  3. Python3.5
  4. ubuntu16.4

搭建網絡

  1. MLP
  2. 隨意搭建的淺層CNN
  3. VGG
  4. ResNet

使用數據集

  1. mnist(在keras的example模塊中自動下載,如果電腦不在實驗室,需要科學上網輔助)
  2. cifar10(同上)
  3. asl美式手語數據集,識別A-E五類。共15000個數據,13600的訓練集、1280的驗證集、120的測試集

五個腳本

一些重要信息在程序註釋裏都解釋了,這裏就不多說了,自己研究研究就明白了。

數據加載腳本dataloader.py

import cv2
import numpy as np
import random
import keras
import os

class Dataloader():
    def __init__(self,path,n_classes = None):
        self.path = path
        self.files = os.listdir(self.path)
        self.n_classes = n_classes


    def load_data(self,name):
        """
        負責將數據一張一張讀入並根據文件名(例23_D)生成標籤,23只是數據的序號,根據
        最後的字母D打標籤
        :param name:數據的路徑
        :return:圖像數據和標籤
        """
        im = cv2.imread(name)
        im = cv2.resize(im,(224,224))
        label = name.split('_')[-1][0]
        if label == 'A':
            label = 0
        elif label == 'B':
            label = 1
        elif label == 'C':
            label = 2
        elif label == 'D':
            label = 3
        elif label == 'E':
            label = 4
        im = np.array(im).astype('float')/255
        label = keras.utils.to_categorical(label,self.n_classes)
        return im,label


    def load_predict_data(self,name,isgray= False,input_size=(28,28)):
        """
        測試模型的時候使用,一次測一張
        :param name: 文件名和路徑
        :param isgray:如果像mnist一類,輸入數據是灰度圖賦值true
        :param input_size:傳入圖像的長寬
        :return: 格式如(1,28,28,1)的數據
        """
        im = cv2.imread(name)
        im = cv2.resize(im,input_size)
        if isgray:
            im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
            im = np.expand_dims(im, axis=2)

        cv2.imshow('im_show', im)
        cv2.waitKey(1000)
        im = np.expand_dims(im, axis=0)
        im = np.array(im).astype('float') / 255
        return im


    def traverse_each_folder(self):
        folders = sorted(os.listdir(self.path))
        sign = 0
        for folder in folders:
            files = os.listdir(self.path+'/'+folder)
            for i in range(len(files)):
                im = cv2.imread(self.path+'/'+folder+'/'+files[i])
                im = cv2.resize(im,(224,224))
            sign+=1
        return np.array(im),sign


    def shuffle(self,path):
        files = os.listdir(path)
        random.shuffle(files)
        cnt=0
        for file in self.files:
            if file[0]=='A':
                os.rename(self.path+'/'+file,self.path+'/'+str(cnt)+'_A.jpg')
            elif file[0]=='B':
                os.rename(self.path+'/'+file,self.path+'/'+str(cnt)+'_B.jpg')
            elif file[0]=='C':
                os.rename(self.path+'/'+file,self.path+'/'+str(cnt)+'_C.jpg')
            elif file[0]=='D':
                os.rename(self.path+'/'+file,self.path+'/'+str(cnt)+'_D.jpg')
            elif file[0]=='E':
                os.rename(self.path+'/'+file,self.path+'/'+str(cnt)+'_E.jpg')
            cnt+=1

class DataGenerator(Dataloader):
    """
    繼承自Dataloader的迭代器類,如果訓練的數據量比較大,就不能在將數據一次性全部讀入內存。
    keras這個時候就需要使用python的生成器來分批次訓練數據。此類只有train_generator的是迭
代器,因爲訓練數據最多。valid_generator只返回數據和標籤的元組
    """
    def __init__(self,path,n_classes):
        Dataloader.__init__(self,path,n_classes)


    def train_generator(self,batch_size):
        X = []
        Y = []
        cnt = 0
        while 1:
            for file in self.files:
                data,label = self.load_data(os.path.join(self.path,file))
                X.append(data)
                Y.append(label)
                cnt+=1
                if cnt==batch_size:
                    cnt=0
                    yield (np.array(X),np.squeeze(np.array(Y)))
                    X = []
                    Y = []


    def valid_generator(self):
        X = []
        Y = []
        for file in self.files:
            data, label = self.load_data(os.path.join(self.path, file))
            X.append(data)
            Y.append(label)
        X = np.array(X)
        Y = np.squeeze(np.array(Y))
        return (X,Y)



模型腳本myNet.py

from keras.models import Sequential,Model
from keras.layers import Input,Flatten,Dropout,regularizers,Add
from keras.layers import Conv2D,BatchNormalization,Activation,MaxPool2D,MaxPooling2D,Dense
from keras.layers import ZeroPadding2D,AveragePooling2D
from keras.optimizers import SGD

class Nets():
    def __init__(self,n_classes,shape = None,fc_size = None):
        self.n_classes = n_classes
        self.shape = shape
        self.fc_size = fc_size

    def MLP(self):
        model = Sequential()
        model.add(Dense(self.fc_size,input_dim = self.fc_size,activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(self.n_classes,activation='softmax'))

        model.compile(loss = 'categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])
        return model

    def CNN(self):
        """
        隨意搭建的普通CNN,mnist直接使用時過擬合現象嚴重,加入了Dropout和l2正則緩解。
        另外使用SGD時經常出現更新停滯,可能是陷入了局部極小值,Adam比較穩定,每次都能更新
        :return: model
        """
        model = Sequential()
        model.add(Conv2D(16,(3,3),activation='relu',input_shape = self.shape))
        model.add(Conv2D(32,(3,3),activation='relu'))
        model.add(MaxPooling2D(pool_size=(2,2)))

        model.add(Conv2D(64,(3,3),activation='relu'))
        model.add(MaxPooling2D(pool_size=(2, 2)))

        model.add(Conv2D(128,(3,3),kernel_regularizer=regularizers.l2(0.1),activation='relu'))
        model.add(MaxPooling2D(pool_size=(2, 2)))

        model.add(Flatten())
        model.add(Dense(256,activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(self.n_classes,activation='softmax'))

        sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
        model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics = ['accuracy'])
        return model


    def VGG(self):
        """
        由於使用自己的筆記本顯卡1050-4G顯存實驗,所以只能跑得動VGG11,層數再多就OOM了。實驗中由於網絡過深出現了梯度
        消失,導致損失不在下降,所以每層後面加入了BN操作後解決。
        :return: VGG11模型
        """
        model = Sequential()
        model.add(Conv2D(64, (3, 3),input_shape=self.shape))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(MaxPool2D(pool_size=(2, 2),strides=(2,2)))

        model.add(Conv2D(128, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(MaxPool2D(pool_size=(2, 2),strides=(2,2)))

        model.add(Conv2D(256, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(Conv2D(256, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(MaxPool2D(pool_size=(2, 2),strides=(2,2)))

        model.add(Conv2D(512, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(Conv2D(512, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))

        model.add(Conv2D(512, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(Conv2D(512, (3, 3)))
        model.add(BatchNormalization(axis=3))
        model.add(Activation('relu'))
        model.add(MaxPool2D(pool_size=(2, 2),strides=(2,2)))

        model.add(Flatten())
        model.add(Dense(1024,activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(256, activation='relu'))
        model.add(Dense(self.n_classes, activation='softmax'))

        model.compile(loss = 'categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])
        return model


    def identity_block(self,x,filters):
        shortcut = x
        f1,f2,f3 = filters

        x = Conv2D(f1,(1,1),padding='valid')(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation('relu')(x)

        x = Conv2D(f2,(3,3),padding='same')(x)
        x = BatchNormalization(axis = 3)(x)
        x = Activation('relu')(x)

        x = Conv2D(f3,(1,1),padding='valid')(x)
        x = BatchNormalization(axis=3)(x)
        x = Add()([x,shortcut])
        x = Activation('relu')(x)

        return x


    def convolutional_block(self,x,filters,stride):
        shortcut = x
        f1,f2,f3 = filters

        x = Conv2D(f1,(1,1),padding='valid',strides=stride)(x)
        x = BatchNormalization(axis = 3)(x)
        x = Activation('relu')(x)

        x = Conv2D(f2, (3,3), padding='same',strides =1)(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation('relu')(x)

        x = Conv2D(f3, (1, 1), padding='valid',strides = 1)(x)
        x = BatchNormalization(axis=3)(x)
        shortcut = Conv2D(f3,(1,1),padding = 'valid',strides = stride)(shortcut)
        shortcut = BatchNormalization(axis=3)(shortcut)

        x = Add()([x,shortcut])
        x = Activation('relu')(x)

        return x


    def basic_block(self,x,filters,stride,name):
        shortcut = x

        x = Conv2D(filters,(3,3),strides=stride,padding='same')(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation('relu')(x)

        x = Conv2D(filters, (3, 3), strides=1,padding='same' )(x)
        x = BatchNormalization(axis=3)(x)

        if x.shape != shortcut.shape:
            shortcut = Conv2D(filters,(1,1),strides = stride,name=name)(shortcut)
            shortcut = BatchNormalization(axis=3)(shortcut)

        x = Add()([x,shortcut])
        x = Activation('relu')(x)

        return x


    def ResNet18(self):
        """
        還是太深的話,筆記本帶不動,ResNet18還可以,該模型比較穩定,參數量小,沒有梯度消失現象
        :return:ResNet18模型
        """
        input = Input(self.shape)

        x = ZeroPadding2D((3,3))(input)
        x = Conv2D(64,(7,7),strides=2)(x)
        x = BatchNormalization(axis = 3)(x)
        x = Activation('relu')(x)
        x = MaxPool2D(pool_size=(3,3),strides = (2,2),padding='same')(x)

        x = self.basic_block(x,64,1,name='shortcut1')
        x = self.basic_block(x,64,1,name='shortcut2')

        x = self.basic_block(x, 128, 2,name='shortcut3')
        x = self.basic_block(x, 128, 1,name='shortcut4')

        x = self.basic_block(x, 256, 2,name='shortcut5')
        x = self.basic_block(x, 256, 1,name='shortcut6')

        x = self.basic_block(x, 512, 2,name='shortcut7')
        x = self.basic_block(x, 512, 1,name='shortcut8')

        size = int(x.shape[1])
        x = AveragePooling2D(pool_size=(size,size))(x)

        x = Flatten()(x)
        x = Dense(self.n_classes,activation='softmax')(x)

        model = Model(inputs = input,outputs=x)
        model.compile(loss = 'categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])

        return model

    def ResNet50(self):
        """
        註釋了好多後筆記本才帶的動
        :return: ResNet50模型
        """
        input = Input(self.shape)

        x = ZeroPadding2D((3,3))(input)
        x = Conv2D(64,(7,7),strides=(2,2))(x)
        x = BatchNormalization(axis = 3)(x)
        x = Activation('relu')(x)
        x = MaxPool2D(pool_size =(3,3),strides=(2,2),padding='same')(x)

        x = self.convolutional_block(x,[64,64,256],stride=1)
        x = self.identity_block(x,[64,64,256])
        # x = self.identity_block(x, [64, 64, 256])

        x = self.convolutional_block(x,[128,128,512],stride=1)
        x = self.identity_block(x,[128,128,512])
        # x = self.identity_block(x, [128, 128, 512])
        # x = self.identity_block(x, [128, 128, 512])
        #
        x = self.convolutional_block(x,[256,256,1024],stride=2)
        x = self.identity_block(x,[256,256,1024])
        # x = self.identity_block(x, [256, 256, 1024])
        # x = self.identity_block(x, [256, 256, 1024])
        # x = self.identity_block(x, [256, 256, 1024])

        x = self.convolutional_block(x,[512,512,2048],stride=2 )
        x = self.identity_block(x,[512,512,2048])
        # x = self.identity_block(x, [512, 512, 2048])

        size = int(x.shape[1])
        x = AveragePooling2D(pool_size=(size, size))(x)

        x = Flatten()(x)
        x = Dense(self.n_classes,activation='softmax')(x)

        model = Model(inputs = input,outputs= x)
        model.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['accuracy'])

        return model

mnist實驗mnist.py

import keras
import cv2
from keras.datasets import mnist
from myNet import Nets
from dataloader import Dataloader

learning_rate = 0.001
training_iters = 20
batch_size = 128
display_step = 10

H, W, C = 28, 28, 1
input_size = H*W
shape = (H,W,C)
n_classes = 10

nets = Nets(n_classes,shape)
model = nets.CNN()
datasets = Dataloader('./test/mnisttest')

def train():
    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    # cv2.imshow('im',x_train[0])
    # cv2.waitKey(1000)
    x_train = x_train.reshape(-1, H, W, 1).astype('float') / 255
    x_test = x_test.reshape(-1, H, W, 1).astype('float') / 255
    y_train = keras.utils.to_categorical(y_train, n_classes)
    y_test = keras.utils.to_categorical(y_test, n_classes)

    model.summary()
    model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=20,batch_size = batch_size)
    # model.save('./model/mnistCNN.h5')
    scores = model.evaluate(x_test,y_test,batch_size=batch_size)
    print(scores)


def test():
    model.load_weights('./model/mnistCNN.h5')
    import os
    import numpy as np
    files = os.listdir(datasets.path)
    for file in files:
        x = datasets.load_predict_data(os.path.join(datasets.path,file),isgray=True)
        y_pred = model.predict(x)  #
        print(np.argmax(y_pred))


if __name__=='__main__':
    train()
    # test()

cifar10實驗cifar10.py

import keras
from keras.datasets import cifar10
from myNet import Nets

H,W,C = 32,32,3
n_classes = 10
shape = (H,W,C)
input_size = H*W*C
batch_size = 128
epoch=30

(x_train,y_train),(x_test,y_test) = cifar10.load_data()
x_train = x_train.reshape(-1,H,W,C).astype('float')/255
x_test = x_test.reshape(-1,H,W,C).astype('float')/255
y_train = keras.utils.to_categorical(y_train,n_classes)
y_test = keras.utils.to_categorical(y_test,n_classes)

nets = Nets(n_classes,shape)

model = nets.ResNet18()
model.summary()

model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=epoch,batch_size=batch_size)
# model.save('./model/cifar10CNN.h5')
score = model.evaluate(x_test,y_test,batch_size=batch_size)
print(score)

asl實驗asl.py

from dataloader import DataGenerator,Dataloader
from myNet import Nets
import numpy as np
import os
import time

H,W,C = 224,224,3
shape = (H,W,C)
n_classes = 5
batch_size = 16
epochs = 10
save_model = './model/aslResNet18.h5'

train_data = DataGenerator('./train',n_classes)
valid_data = DataGenerator('./valid',n_classes).valid_generator()

nets = Nets(n_classes,shape)
model = nets.VGG()

def train():
    model.summary()
    #fit_generator需要使用迭代器
    model.fit_generator(train_data.train_generator(batch_size),epochs=epochs,validation_data= valid_data,steps_per_epoch=len(train_data.files)//batch_size)
    # model.save_weights(save_model)

def test(path):
    model.load_weights(save_model)
    dataloader = Dataloader(path)
    files = (os.listdir(path))
    for file in files:
        test_data = dataloader.load_predict_data(os.path.join(path, file), input_size=(H, W))
        time_start = time.time()
        result = model.predict(test_data)
        time_end = time.time()
        pred = np.argmax(result, axis=1)
        print('classes : %s \t cost : %04f s'%(pred,time_end-time_start))


if __name__ =='__main__':
    train()
    data_path= './test/asltest'
    # test(data_path)


 

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