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搭建神經網絡識別三類數據練習
環境說明
- keras2.0
- 後端tensorflow-gpu版1.6
- Python3.5
- ubuntu16.4
搭建網絡
- MLP
- 隨意搭建的淺層CNN
- VGG
- ResNet
使用數據集
- mnist(在keras的example模塊中自動下載,如果電腦不在實驗室,需要科學上網輔助)
- cifar10(同上)
- 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)