1. lenet5

图像分类卷积神经网络_tensorflow

def lenet5_1(input_shape,classiers_n): #lenet5
inputShape = input_shape
model = tf.keras.Sequential([
Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation='relu',input_shape=inputShape),
AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
Conv2D(filters=12,kernel_size=(5,5),padding='valid',activation='relu'),
AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
Flatten(),
Dense(units=312,activation='relu'),
Dense(units=156,activation='relu'),
Dense(units=CLASSIERS_N,activation='softmax'),
])
model.summary()
def lenet5(input_shape,classiers_n): #lenet5
input = Input(input_shape)
conv1 = Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation='relu')(input)
pool1 = AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same')(conv1)
conv2 = Conv2D(filters=12,kernel_size=(5,5),padding='valid',activation='relu')(pool1)
pool2 = AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same')(conv2)
flatten = Flatten()(pool2)
dense1 = Dense(units=312,activation='relu')(flatten)
dense2 = Dense(units=156,activation='relu')(dense1)
dense3 = Dense(units=classiers_n,activation='softmax')(dense2)
model = Model(input,dense3)
return model
class letnet5(Layer): #lenet5
def __init__(self,classiers_n):
super(lenet5,self).__init__()
self.conv1 = Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation='relu')
self.pool1 = AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same')
self.conv2 = Conv2D(filters=12,kernel_size=(5,5),padding='valid',activation='relu')
self.pool2 = AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same')
self.flatten = Flatten()
self.dense1 = Dense(units=312,activation='relu')
self.dense2 = Dense(units=156,activation='relu')
self.dense3 = Dense(units=classiers_n,activation='softmax')

def call(self, input):
x = self.conv1(input)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.flatten(x)
x = self.dense1(x)
x = self.dense2(x)
out = self.dense3(x)
return out


def get_config(self): #在有自定义网络层时,需要保存模型时,重写get_config函数
config = {"conv1": self.conv1,"pool1":self.pool1,"conv2":self.conv2,"pool2":self.pool2,"flatten":self.flatten,"dense1":self.dense1,"dense2":self.dense2,"dense3":self.dense3}
base_config = super(lenet5, self).get_config()
return dict(list(base_config.items()) + list(config.items()))

def Letnet5(input_shape,classiers_n):
input = Input(input_shape)
out = lenet5(classiers_n)(input)
model = Model(input,out)
return model

说明:
lenet5_1构建简单网络使用;
lenet5构建复杂网络,可以在此网络进行其他操作;
letnet5通过自定义层,来实现lenet5网络的构建;
后面两种可以轻易扩展横向深度,
三种写法实际上没有本质区别。

2. alxnet

图像分类卷积神经网络_cnn_02

def Alexnet(input_shape,classier_n):
inputShape = input_shape
model = Sequential()
model.add(Conv2D(96,(11,11),strides=(4,4),input_shape=inputShape,padding="same"))
model.add(Activation("relu"))#relu函数的作用就是增加了神经网络各层之间的非线性关系
model.add(BatchNormalization())#加快训练过程并提高性能;解决梯度消失的问题;规范权重;优化网络梯度流
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25))#训练样本过少时,明显地减少过拟合现象。
model.add(Conv2D(256,(5,5),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25))
model.add(Conv2D(384,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Conv2D(384,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Conv2D(256,(3,3),padding="same"))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(4096))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.25))
model.add(Dense(4096))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.25))
model.add(Dense(classier_n))
model.add(Activation("softmax"))
return model

说明:在lenet5的基础上加深了网络,引入了relu函数,
增加了神经网络各层之间的非线性关系。
引入了dropout层,训练样本过少时,明显地减少过拟合现象。

3.vggnet

图像分类卷积神经网络_2d_03

def vggnet(input_shape,classier_n):
inputShape = input_shape
model = Sequential()
model.add(Conv2D(64, kernel_size=(3,3), strides=(1, 1) , activation='relu',padding='same',input_shape=inputShape))
model.add(Conv2D(64, kernel_size=(3,3), strides=(1, 1) , activation='relu',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(128, kernel_size=(3,3), strides=(1, 1) , activation='relu',padding='same'))
model.add(Conv2D(128, kernel_size=(3,3), strides=(1, 1) , activation='relu',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(256, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(Conv2D(256, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(Conv2D(256, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) , activation='relu',padding='same'))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(Conv2D(512, kernel_size=(3,3), strides=(1, 1) ,activation='relu',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
model.add(Flatten())
model.add(Dense(4096))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(4096))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(classier_n))
model.add(Activation("softmax"))
return model

说明:
与alxnet相比使用了更小的卷积核,证明了:
证明了使用很小的卷积(3*3),增加网络深度可以有效提升模型的效果,
而且VGGNet对其他数据集具有很好的泛化能力。

4.gooLenet

图像分类卷积神经网络_cnn_04


图像分类卷积神经网络_tensorflow_05

def AuxiliaryClassifier(input,name):
flatten = Flatten()(input)
fc1 = Dense(units=1024,activation="relu")(flatten)
dropout = Dropout(rate=0.7)(fc1)
fc2 = Dense(units=1000,activation="softmax")(dropout)
return fc2


def Inception(input,nb_filter,name):
branch1x1 = Conv2D(nb_filter[0],(1,1), padding='same',strides=(1,1),name=None)(input)
branch3x3 = Conv2D(nb_filter[1],(1,1), padding='same',strides=(1,1),name=None)(input)
branch3x3 = Conv2D(nb_filter[2],(3,3), padding='same',strides=(1,1),name=None)(branch3x3)
branch5x5 = Conv2D(nb_filter[3],(1,1), padding='same',strides=(1,1),name=None)(input)
branch5x5 = Conv2D(nb_filter[4],(5,5), padding='same',strides=(1,1),name=None)(branch5x5)
branchpool = MaxPooling2D(pool_size=(3,3),strides=(1,1),padding='same')(input)
branchpool = Conv2D(nb_filter[5],(1,1),padding='same',strides=(1,1),name=None)(branchpool)
Inception_output = concatenate([branch1x1,branch3x3,branch5x5,branchpool],axis=3)
return Inception_output

def goolenet(input_shape,classier_n):
net = {}
input_shape = Input(shape=input_shape)
x = input_shape
x = Conv2D(64,(7,7),strides=(2,2),padding="same")(x)
x = MaxPooling2D(pool_size=(3,3),strides=(2,2))(x)
x = Conv2D(192,(1,1),strides=(2,2),padding="same")(x)
x = Conv2D(192,(3,3),strides=(2,2),padding="same")(x)
x = MaxPooling2D(pool_size=(3,3),strides=(2,2))(x)
x = Inception(x,[64,96,128,16,32,32],name='inception-3a')
x = Inception(x,[128,128,192,32,96,64],name='inception-3b')
x = MaxPool2D(pool_size=3,strides=2,padding='same',name='max-pool-3')(x)
x = Inception(x,[192,96,208,16,48,64],name='inception-4a')
outputs1 = AuxiliaryClassifier(x,name='AuxiliaryClassifier-1')
x = Inception(x,[160,112,224,24,64,64],name='inception-4b')
x = Inception(x,[128,128,256,24,64,64],name='inception-4c')
x = Inception(x,[112,144,288,32,64,64],name='inception-4d')
outputs2 = AuxiliaryClassifier(x,name='AuxiliaryClassifier-2')
x = Inception(x,[256,160,320,32,128,128],name='inception-4e')
x = MaxPool2D(pool_size=3,strides=2,padding='same',name='max-pool-4')(x)
x = Inception(x,[256,160,320,32,128,128],name='inception-5a')
x = Inception(x,[384,192,384,48,128,128],name='inception-5b')
x = Flatten(name='flatten')(x)
x = Dropout(rate=0.4,name='dropout')(x)
x = Dense(units=classier_n,name='linear')(x)
outputs = Softmax(name='softmax')(x)
model = Model(inputs=input_shape,outputs=outputs,name='GoogLeNet')
return model

说明:
googLenet最大的特点就是扩展了横向深度,将不同维度,
不同大小卷积核提取的特征结合到一起。以保证提取更多的特征。

5. resnet

图像分类卷积神经网络_cnn_06


图像分类卷积神经网络_cnn_07

class prepare(layers.Layer):

def __init__(self):
super(prepare, self).__init__()
self.conv1=layers.Conv2D(64,(3,3),strides=1,padding="same")
self.bn=layers.BatchNormalization()
self.Relu=layers.Activation('relu')
self.mp=layers.MaxPool2D(pool_size=(2,2),strides=2)

def call(self,inputs):
x=self.conv1(inputs)
x=self.bn(x)
x=self.Relu(x)
x=self.mp(x)
return x

def get_config(self): #在有自定义网络层时,需要保存模型时,重写get_config函数
config = {"conv1": self.conv1,"bn":self.bn,"Relu":self.Relu,"mp":self.mp}
base_config = super(prepare, self).get_config()
return dict(list(base_config.items()) + list(config.items()))

class block(layers.Layer):
def __init__(self,filter_num,stride=1,is_first=False):
super(block,self).__init__()
self.conv1=layers.Conv2D(filter_num,(1,1),strides=1)
self.bn1=layers.BatchNormalization()

self.conv2=layers.Conv2D(filter_num,(3,3),strides=stride,padding='same')
self.bn2=layers.BatchNormalization()

self.conv3=layers.Conv2D(filter_num*4,(1,1),strides=1)
self.bn3=layers.BatchNormalization()

self.relu=layers.Activation('relu')
if stride!=1 or is_first==True:
self.downsample=Sequential()
self.downsample.add(layers.Conv2D(filter_num*4,(1,1),strides=stride))
else:
self.downsample=lambda x:x
def call(self,inputs):
x=self.conv1(inputs)
x=self.bn1(x)
x=self.relu(x)

x=self.conv2(x)
x=self.bn2(x)
x=self.relu(x)

x=self.conv3(x)
x=self.bn3(x)

identity=self.downsample(inputs)
output=layers.add([x,identity])
output=tf.nn.relu(output)
return output

def get_config(self): #在有自定义网络层时,需要保存模型时,重写get_config函数
config = {"conv1": self.conv1,"bn1":self.bn1,"conv2": self.conv2,"bn2":self.bn2,"conv3": self.conv3,"bn3":self.bn3,"relu":self.relu,"downsample":self.downsample}
base_config = super(block, self).get_config()
return dict(list(base_config.items()) + list(config.items()))

def Resnet(input_shape,num_classes):
input_image = layers.Input(shape=input_shape, dtype="float32")
out=prepare()(input_image)
out=block(64,is_first=True)(out)
out=block(64)(out)
out=block(64)(out)
out=block(128,stride=2)(out)
out=block(128)(out)
out=block(128)(out)
out=block(256,stride=2)(out)
out=block(256)(out)
out=block(256)(out)
out=block(512,stride=2)(out)
out=block(512)(out)
out=block(512)(out)
out=layers.GlobalAveragePooling2D()(out)
out=layers.Dense(num_classes)(out)
out-layers.Activation('relu')(out)
return keras.Model(inputs=input_image, outputs=out)

说明:
最大的特点引入了残差模块,一条路线恒等变换,
一条路线残差网络计算,最后将两个路线结果相加,
以增加网络特征。目前被广泛使用的网络。

6.数据集制作

def tf_dataset(filepath,dict_classiers,input_shape,radio_images=0.8):
if filepath=="":
return False
file_dataset_init = glob(filepath+"/*/*.jpg") + glob(filepath+"/*/*.png")
image_len_dataset_init = len(file_dataset_init)


random.shuffle(file_dataset_init)
file_dataset = random.sample(file_dataset_init,int(image_len_dataset_init*radio_images))
image_len_dataset = len(file_dataset)
if image_len_dataset==0:
return False

train_x = np.zeros((image_len_dataset,input_shape[0],input_shape[1],input_shape[2]))
train_y = np.zeros((image_len_dataset))
np.random.shuffle(train_x)
for index,filename in enumerate(file_dataset):
image = cv2.imread(filename)
image = cv2.resize(image, (input_shape[0],input_shape[1])) /255.0
label = dict_classiers[filename.split("\\")[-2]]
train_x[index] = image
train_y[index] = label
return train_x,train_y
def tf_generate(x_train,y_train):
dataset = tf.data.Dataset.from_tensor_slices((x_train,y_train))
dataset = dataset.repeat()
dataset = dataset.shuffle(100).batch(1).repeat()
return dataset

tf_datasetd

filepath 数据集路径
dict_classiers数据集下类别对应字典;例如,{‘cat’: 0, ‘panda’: 1}。
input_shape 输入形状大小
radio_images 数据使用比例,防止数据量多大内存不足,
也可以改为训练与测试的数据占比(本文中没有使用测试集)。
return train_x,train_y 返回训练集图像及标签。

tf_generate

tf_generate参数为tf_datasetd的的返回结果
tf_generate返回值为dataset,类似于迭代器,减少内存使用。

7. 模型训练

def plot(history,filename):
pd.DataFrame(history.history).plot(figsize=(8,5))
plt.grid(True)
plt.gca().set_ylim(0,3)
plt.gca().set_xlim(0,50)
plt.savefig(filename)

def train_model(datasets_path):
save_model_name = "resnet_model.h5"
radio_images = 1
dict_classiers = {value:index for index,value in enumerate(os.listdir(datasets_path))}
classiers_n = 2
epochs = 20
learn_rate = 0.000001
use_adam_is = False
file_dataset_init = glob(datasets_path+"/*/*.jpg") + glob(datasets_path+"/*/*.png")
input_shape = (112,112,3)
batch_size = 16
train_x,train_y = tf_dataset(datasets_path,dict_classiers,input_shape,radio_images)
model = Resnet(input_shape,num_classes=classiers_n)
model.summary()
if (use_adam_is == True):
Adam_optimizer = Adam(lr=learn_rate)
model.compile(loss="SparseCategoricalCrossentropy", optimizer=Adam_optimizer,metrics=["accuracy"])
else:
model.compile(loss="SparseCategoricalCrossentropy", optimizer="adam",metrics=["accuracy"])
history = model.fit(train_x, train_y, batch_size=batch_size,epochs=epochs)
model.save(save_model_name)
plot_filename = save_model_name.replace(".h5",".png")
plot(history,plot_filename)
train_model(datasets_path)

train_model:

参数为数据集路径;

plot(history,filename):

参数为model.fit返回结果以及可视化结果图片的名称。

图像分类卷积神经网络_分类_08