图像分类卷积神经网络

1. lenet5

请添加图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述


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

在这里插入图片描述
在这里插入图片描述

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返回结果以及可视化结果图片的名称。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佐倉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值