keras实现多种分类网络的方式
程序员文章站
2022-03-03 21:25:43
keras应该是最简单的一种深度学习框架了,入门非常的简单.简单记录一下keras实现多种分类网络:如alexnet、vgg、resnet采用kaggle猫狗大战的数据作为数据集.由于alexnet采...
keras应该是最简单的一种深度学习框架了,入门非常的简单.
简单记录一下keras实现多种分类网络:如alexnet、vgg、resnet
采用kaggle猫狗大战的数据作为数据集.
由于alexnet采用的是lrn标准化,keras没有内置函数实现,这里用batchnormalization代替
收件建立一个model.py的文件,里面存放着alexnet,vgg两种模型,直接导入就可以了
#coding=utf-8 from keras.models import sequential from keras.layers import dense, dropout, activation, flatten from keras.layers import conv2d, maxpooling2d, zeropadding2d, batchnormalization from keras.layers import * from keras.layers.advanced_activations import leakyrelu,prelu from keras.models import model def keras_batchnormalization_relu(layer): bn = batchnormalization()(layer) ac = prelu()(bn) return ac def alexnet(resize=227, classes=2): model = sequential() # 第一段 model.add(conv2d(filters=96, kernel_size=(11, 11), strides=(4, 4), padding='valid', input_shape=(resize, resize, 3), activation='relu')) model.add(batchnormalization()) model.add(maxpooling2d(pool_size=(3, 3), strides=(2, 2), padding='valid')) # 第二段 model.add(conv2d(filters=256, kernel_size=(5, 5), strides=(1, 1), padding='same', activation='relu')) model.add(batchnormalization()) model.add(maxpooling2d(pool_size=(3, 3), strides=(2, 2), padding='valid')) # 第三段 model.add(conv2d(filters=384, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu')) model.add(conv2d(filters=384, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu')) model.add(conv2d(filters=256, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu')) model.add(maxpooling2d(pool_size=(3, 3), strides=(2, 2), padding='valid')) # 第四段 model.add(flatten()) model.add(dense(4096, activation='relu')) model.add(dropout(0.5)) model.add(dense(4096, activation='relu')) model.add(dropout(0.5)) model.add(dense(1000, activation='relu')) model.add(dropout(0.5)) # output layer model.add(dense(classes,activation='softmax')) # model.add(activation('softmax')) return model def alexnet2(inputs, classes=2, prob=0.5): ''' 自己写的函数,尝试keras另外一种写法 :param inputs: 输入 :param classes: 类别的个数 :param prob: dropout的概率 :return: 模型 ''' # conv2d(32, (3, 3), dilation_rate=(2, 2), padding='same')(inputs) print "input shape:", inputs.shape conv1 = conv2d(filters=96, kernel_size=(11, 11), strides=(4, 4), padding='valid')(inputs) conv1 = keras_batchnormalization_relu(conv1) print "conv1 shape:", conv1.shape pool1 = maxpool2d(pool_size=(3, 3), strides=(2, 2))(conv1) print "pool1 shape:", pool1.shape conv2 = conv2d(filters=256, kernel_size=(5, 5), padding='same')(pool1) conv2 = keras_batchnormalization_relu(conv2) print "conv2 shape:", conv2.shape pool2 = maxpool2d(pool_size=(3, 3), strides=(2, 2))(conv2) print "pool2 shape:", pool2.shape conv3 = conv2d(filters=384, kernel_size=(3, 3), padding='same')(pool2) conv3 = prelu()(conv3) print "conv3 shape:", conv3.shape conv4 = conv2d(filters=384, kernel_size=(3, 3), padding='same')(conv3) conv4 = prelu()(conv4) print "conv4 shape:", conv4 conv5 = conv2d(filters=256, kernel_size=(3, 3), padding='same')(conv4) conv5 = prelu()(conv5) print "conv5 shape:", conv5 pool3 = maxpool2d(pool_size=(3, 3), strides=(2, 2))(conv5) print "pool3 shape:", pool3.shape dense1 = flatten()(pool3) dense1 = dense(4096, activation='relu')(dense1) print "dense2 shape:", dense1 dense1 = dropout(prob)(dense1) # print "dense1 shape:", dense1 dense2 = dense(4096, activation='relu')(dense1) print "dense2 shape:", dense2 dense2 = dropout(prob)(dense2) # print "dense2 shape:", dense2 predict= dense(classes, activation='softmax')(dense2) model = model(inputs=inputs, outputs=predict) return model def vgg13(resize=224, classes=2, prob=0.5): model = sequential() model.add(conv2d(64, (3, 3), strides=(1, 1), input_shape=(resize, resize, 3), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(64, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(128, (3, 2), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(flatten()) model.add(dense(4096, activation='relu')) model.add(dropout(prob)) model.add(dense(4096, activation='relu')) model.add(dropout(prob)) model.add(dense(classes, activation='softmax')) return model def vgg16(resize=224, classes=2, prob=0.5): model = sequential() model.add(conv2d(64, (3, 3), strides=(1, 1), input_shape=(resize, resize, 3), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(64, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(128, (3, 2), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(conv2d(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform')) model.add(maxpooling2d(pool_size=(2, 2))) model.add(flatten()) model.add(dense(4096, activation='relu')) model.add(dropout(prob)) model.add(dense(4096, activation='relu')) model.add(dropout(prob)) model.add(dense(classes, activation='softmax')) return model
然后建立一个train.py文件,用于读取数据和训练数据的.
#coding=utf-8 import keras import cv2 import os import numpy as np import model import modelresnet import tensorflow as tf from keras.layers import input, dense from keras.preprocessing.image import imagedatagenerator resize = 224 batch_size = 128 path = "/home/hjxu/pycharmprojects/01_cats_vs_dogs/data" traindirectory = '/home/hjxu/pycharmprojects/01_cats_vs_dogs/data/train/' def load_data(): imgs = os.listdir(path + "/train/") num = len(imgs) train_data = np.empty((5000, resize, resize, 3), dtype="int32") train_label = np.empty((5000, ), dtype="int32") test_data = np.empty((5000, resize, resize, 3), dtype="int32") test_label = np.empty((5000, ), dtype="int32") for i in range(5000): if i % 2: train_data[i] = cv2.resize(cv2.imread(path + '/train/' + 'dog.' + str(i) + '.jpg'), (resize, resize)) train_label[i] = 1 else: train_data[i] = cv2.resize(cv2.imread(path + '/train/' + 'cat.' + str(i) + '.jpg'), (resize, resize)) train_label[i] = 0 for i in range(5000, 10000): if i % 2: test_data[i-5000] = cv2.resize(cv2.imread(path + '/train/' + 'dog.' + str(i) + '.jpg'), (resize, resize)) test_label[i-5000] = 1 else: test_data[i-5000] = cv2.resize(cv2.imread(path + '/train/' + 'cat.' + str(i) + '.jpg'), (resize, resize)) test_label[i-5000] = 0 return train_data, train_label, test_data, test_label def main(): train_data, train_label, test_data, test_label = load_data() train_data, test_data = train_data.astype('float32'), test_data.astype('float32') train_data, test_data = train_data/255, test_data/255 train_label = keras.utils.to_categorical(train_label, 2) ''' #one_hot转码,如果使用 categorical_crossentropy,就需要用到to_categorical函数完成转码 ''' test_label = keras.utils.to_categorical(test_label, 2) inputs = input(shape=(224, 224, 3)) modelalex = model.alexnet2(inputs, classes=2) ''' 导入模型 ''' modelalex.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) ''' def compile(self, optimizer, loss, metrics=none, loss_weights=none, sample_weight_mode=none, **kwargs): optimizer:优化器,为预定义优化器名或优化器对象,参考优化器 loss: 损失函数,为预定义损失函数名或者一个目标函数 metrics:列表,包含评估模型在训练和测试时的性能指标,典型用法是 metrics=['accuracy'] sample_weight_mode:如果需要按时间步为样本赋值,需要将改制设置为"temoral" 如果想用自定义的性能评估函数:如下 def mean_pred(y_true, y_pred): return k.mean(y_pred) model.compile(loss = 'binary_crossentropy', metrics=['accuracy', mean_pred],...) 损失函数同理,再看 keras内置支持的损失函数有 mean_squared_error mean_absolute_error mean_absolute_percentage_error mean_squared_logarithmic_error squared_hinge hinge categorical_hinge logcosh categorical_crossentropy sparse_categorical_crossentropy binary_crossentropy kullback_leibler_divergence poisson cosine_proximity ''' modelalex.summary() ''' # 打印模型信息 ''' modelalex.fit(train_data, train_label, batch_size=batch_size, epochs=50, validation_split=0.2, shuffle=true) ''' def fit(self, x=none, # x:输入数据 y=none, # y:标签 numpy array batch_size=32, # batch_size:训练时,一个batch的样本会被计算一次梯度下降 epochs=1, # epochs: 训练的轮数,每个epoch会把训练集循环一遍 verbose=1, # 日志显示:0表示不在标准输入输出流输出,1表示输出进度条,2表示每个epoch输出 callbacks=none, # 回调函数 validation_split=0., # 0-1的浮点数,用来指定训练集一定比例作为验证集,验证集不参与训练 validation_data=none, # (x,y)的tuple,是指定的验证集 shuffle=true, # 如果是"batch",则是用来处理hdf5数据的特殊情况,将在batch内部将数据打乱 class_weight=none, # 字典,将不同的类别映射为不同的权值,用来在训练过程中调整损失函数的 sample_weight=none, # 权值的numpy array,用于训练的时候调整损失函数 initial_epoch=0, # 该参数用于从指定的epoch开始训练,继续之前的训练 **kwargs): 返回:返回一个history的对象,其中history.history损失函数和其他指标的数值随epoch变化的情况 ''' scores = modelalex.evaluate(train_data, train_label, verbose=1) print(scores) scores = modelalex.evaluate(test_data, test_label, verbose=1) print(scores) modelalex.save('my_model_weights2.h5') def main2(): train_datagen = imagedatagenerator(rescale=1. / 255, shear_range=0.2, zoom_range=0.2, horizontal_flip=true) test_datagen = imagedatagenerator(rescale=1. / 255) train_generator = train_datagen.flow_from_directory(traindirectory, target_size=(224, 224), batch_size=32, class_mode='binary') validation_generator = test_datagen.flow_from_directory(traindirectory, target_size=(224, 224), batch_size=32, class_mode='binary') inputs = input(shape=(224, 224, 3)) # modelalex = model.alexnet2(inputs, classes=2) modelalex = model.vgg13(resize=224, classes=2, prob=0.5) # modelalex = modelresnet.resnet50(shape=224, classes=2) modelalex.compile(loss='sparse_categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) modelalex.summary() modelalex.fit_generator(train_generator, steps_per_epoch=1000, epochs=60, validation_data=validation_generator, validation_steps=200) modelalex.save('model32.hdf5') # if __name__ == "__main__": ''' 如果数据是按照猫狗大战的数据,都在同一个文件夹下,使用main()函数 如果数据按照猫和狗分成两类,则使用main2()函数 ''' main2()
得到模型后该怎么测试一张图像呢?
建立一个testoneimg.py脚本,代码如下
#coding=utf-8 from keras.preprocessing.image import load_img#load_image作用是载入图片 from keras.preprocessing.image import img_to_array from keras.applications.vgg16 import preprocess_input from keras.applications.vgg16 import decode_predictions import numpy as np import cv2 import model from keras.models import sequential pats = '/home/hjxu/tf_study/catvsdogswithkeras/my_model_weights.h5' modelalex = model.alexnet(resize=224, classes=2) # alexmodel = model.alexnet(weightpath='/home/hjxu/tf_study/catvsdogswithkeras/my_model_weights.h5') modelalex.load_weights(pats) # img = cv2.imread('/home/hjxu/tf_study/catvsdogswithkeras/111.jpg') img = cv2.resize(img, (224, 224)) x = img_to_array(img/255) # 三维(224,224,3) x = np.expand_dims(x, axis=0) # 四维(1,224,224,3)#因为keras要求的维度是这样的,所以要增加一个维度 # x = preprocess_input(x) # 预处理 print(x.shape) y_pred = modelalex.predict(x) # 预测概率 t1 = time.time() print("测试图:", decode_predictions(y_pred)) # 输出五个最高概率(类名, 语义概念, 预测概率) print y_pred
不得不说,keras真心简单方便。
补充知识:keras中的函数式api——残差连接+权重共享的理解
1、残差连接
# coding: utf-8 """残差连接 residual connection: 是一种常见的类图网络结构,解决了所有大规模深度学习的两个共性问题: 1、梯度消失 2、表示瓶颈 (甚至,向任何>10层的神经网络添加残差连接,都可能会有帮助) 残差连接:让前面某层的输出作为后面某层的输入,从而在序列网络中有效地创造一条捷径。 """ from keras import layers x = ... y = layers.conv2d(128, 3, activation='relu', padding='same')(x) y = layers.conv2d(128, 3, activation='relu', padding='same')(y) y = layers.conv2d(128, 3, activation='relu', padding='same')(y) y = layers.add([y, x]) # 将原始x与输出特征相加 # ---------------------如果特征图尺寸不同,采用线性残差连接------------------- x = ... y = layers.conv2d(128, 3, activation='relu', padding='same')(x) y = layers.conv2d(128, 3, activation='relu', padding='same')(y) y = layers.maxpooling2d(2, strides=2)(y) residual = layers.conv2d(128, 1, strides=2, padding='same')(x) # 使用1*1的卷积,将原始张量线性下采样为y具有相同的形状 y = layers.add([y, residual]) # 将原始x与输出特征相加
2、权重共享
即多次调用同一个实例
# coding: utf-8 """函数式子api:权重共享 能够重复的使用同一个实例,这样相当于重复使用一个层的权重,不需要重新编写""" from keras import layers from keras import input from keras.models import model lstm = layers.lstm(32) # 实例化一个lstm层,后面被调用很多次 # ------------------------左边分支-------------------------------- left_input = input(shape=(none, 128)) left_output = lstm(left_input) # 调用lstm实例 # ------------------------右分支--------------------------------- right_input = input(shape=(none, 128)) right_output = lstm(right_input) # 调用lstm实例 # ------------------------将层进行连接合并------------------------ merged = layers.concatenate([left_output, right_output], axis=-1) # -----------------------在上面构建一个分类器--------------------- predictions = layers.dense(1, activation='sigmoid')(merged) # -------------------------构建模型,并拟合训练----------------------------------- model = model([left_input, right_input], predictions) model.fit([left_data, right_data], targets)
以上这篇keras实现多种分类网络的方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。