卷积神经网络模型

编写不易,未有VIP但想白嫖文章的朋友可以关注我的个人公众号“不秃头的码农”直接查看文章,后台回复java资料、单片机、安卓可免费领取资源。你的支持是我最大的动力!
在这里插入图片描述

ResNet残缺模型

import tensorflow as tf
import os
import numpy as np
from matplotlib import pyplot as plt
import pandas as pd
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, Dense
from tensorflow.keras import Model
import cv2
from PIL import Image
#resnet残缺模型
np.set_printoptions(threshold=np.inf)  #打印完整的数组阵列,一般打印时太多的话中间部分会省略

train_path = './shujuji/data/'
train_txt = './shujuji/training.csv'  #放训练集,里面的字段FileID与data目录下的图片名对应,SpeciesID字段与species.csv的物种信息对应

test_path = './shujuji/data/'
test_txt = './shujuji/annotation.csv' #标注数据清单,用于对数据预测的结果进行校验和评分,字段和上面一样


#图像预处理
def generateds(path, txt):
    df = pd.read_csv(txt)   #读取csv文件,将他们的数据字段分别存到数组中
    contents = np.array(df['FileID'])
    value = np.array(df['SpeciesID'])
    x, y_ = [], []  # 建立空列
    lenth = len(contents)  #获取数组长度用于遍历

    for content in range(lenth):  # 逐行取出
        img_path = path + contents[content] + '.jpg'  # 拼出图片路径和文件名
        img = Image.open(img_path)  # 读入图片
        img = np.float32(img)     #将图片变成32位高精度的数组
        h, w, _ = img.shape  #得到它的高和宽
        scale = min(64 / w, 64 / h)   # 64是需要的图片尺寸,不改变图像的宽高比例,防止失真(64/w这就是宽的比例)
        nw, nh = int(scale * w), int(scale * h)
        image_resized = cv2.resize(img, (nw, nh))  #缩放图像变成64*64(简单的正方形转换,把图片转为正方形)
        image_paded = np.full(shape=[64, 64, 3], fill_value=120) #得到3个用120的值填充一个64行64列的数组(对应rgb3张图片)
        dw, dh = (64 - nw) // 2, (64 - nh) // 2   #宽和高分别要扩展的像素数
        image_paded[dh:nh + dh, dw:nw + dw, :] = image_resized   #把图片填充到数组位置,填充后120被替换成图片的像素值(变成有数字的矩阵)
        image_paded = image_paded / 255.  # 数据归一化,使值都趋于0(0-1之间),都是些0点几的数,保持像素值为正数(实现预处理)
        x.append(image_paded)  # 归一化后的数据,贴到列表x
        y_.append(value[content])  # 标签贴到列表y_
        print('loading : ' + img_path)  # 打印状态提示

    x = np.array(x)  # 变为np.array格式(想象成图片集,但这些图片是像素矩阵)
    y_ = np.array(y_)  # 变为np.array格式
    y_ = y_.astype(np.int64)  # 变为64位整型
    return x, y_  # 返回输入特征x,返回标签y_

#调用图像预处理
x_train, y_train = generateds(train_path, train_txt)
x_test, y_test = generateds(test_path, test_txt)
print(x_train.shape)


#resnet卷积模型(深度残差网络)的残差模块
class ResnetBlock(Model):
    #初始化
    def __init__(self, filters, strides=1, residual_path=False):
        super(ResnetBlock, self).__init__()
        self.filters = filters
        self.strides = strides
        self.residual_path = residual_path

        #第1个部分: CBAPD搭建要用到的神经网络的每一层结构,并进行特征提取
        self.c1 = Conv2D(filters, (3, 3), strides=strides, padding='same', use_bias=False)  #filters个卷积核,卷积核大小为3*3,使用全0填充
        self.b1 = BatchNormalization()  #BN操作:批标准化
        self.a1 = Activation('relu')   #激活函数使用relu
        self.d1 = Dropout(0.3)         #按照30%的比例休眠神经元
        # 第2个部分
        self.c2 = Conv2D(filters, (3, 3), strides=1, padding='same', use_bias=False)  #strides=1表示一维张量
        self.b2 = BatchNormalization()

        # residual_path为True时(堆叠卷积层维度不同),对输入进行下采样,即用1x1的卷积核做卷积操作,保证x能和F(x)维度相同,顺利相加;因为跳过叠加层数时维度不同
        if residual_path:
            self.down_c1 = Conv2D(filters, (1, 1), strides=strides, padding='same', use_bias=False)
            self.down_b1 = BatchNormalization()

        self.a2 = Activation('relu')  #通过relu激活


    def call(self, inputs):
        residual = inputs  # residual等于输入值本身,即residual=x
        # 第1个部分: 将输入通过卷积、BN层、激活层,计算F(x)
        x = self.c1(inputs)
        x = self.b1(x)
        x = self.a1(x)
        x = self.d1(x)
        # 第2个部分
        x = self.c2(x)
        y = self.b2(x)

        # residual_path为True时(堆叠卷积层维度不同):调整输入特征图inputs的尺寸或深度
        if self.residual_path:
            residual = self.down_c1(inputs)
            residual = self.down_b1(residual)

        out = self.a2(y + residual)  # 最后输出的是两部分的和,即F(x)+x或F(x)+Wx,再过激活函数,y为堆叠卷积输出特征,residual为输入特征值inputs
        return out


class ResNet18(Model):  #18层网络:第一层是个卷积,中间有8层resnet块,每个resnet块又有2层卷积,最后有一层全连接

    def __init__(self, block_list, initial_filters=64):  # block_list表示每个block有几个卷积层
        super(ResNet18, self).__init__()
        self.num_blocks = len(block_list)  # 共有几个block(resnet块)
        self.block_list = block_list
        self.out_filters = initial_filters
        self.c1 = Conv2D(self.out_filters, (3, 3), strides=1, padding='same', use_bias=False)
        self.b1 = BatchNormalization()
        self.a1 = Activation('relu')
        self.blocks = tf.keras.models.Sequential()
        # 构建ResNet网络结构
        for block_id in range(len(block_list)):  # 第几个resnet block(4个)
            for layer_id in range(block_list[block_id]):  # 第几个卷积层
                #先虚线后实线
                if block_id != 0 and layer_id == 0:  # 对除第一个block以外的每个block的输入进行下采样
                    block = ResnetBlock(self.out_filters, strides=2, residual_path=True)  #用虚线连接
                else:
                    block = ResnetBlock(self.out_filters, residual_path=False)   #用实现连接
                self.blocks.add(block)  # 将构建好的block加入resnet
            self.out_filters *= 2  # 下一个block的卷积核数是上一个block的2倍(可以改!!!)
        self.p1 = tf.keras.layers.GlobalAveragePooling2D()
        self.d2 = Dropout(0.3)  #按照30%的比例休眠神经元,改!!!
        self.f1 = tf.keras.layers.Dense(20, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())

    def call(self, inputs):
        x = self.c1(inputs)
        x = self.b1(x)
        x = self.a1(x)
        x = self.blocks(x)
        x = self.p1(x)
        x = self.d2(x)
        y = self.f1(x)
        return y

# 调用ResNet18运行,一共4个元素,所以block(块)执行4次,每次有2个(看图)---->改!!
model = ResNet18([2, 2, 2, 2])

# 设置优化器
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

#加载模型
checkpoint_save_path = "./checkpoint/ResNet18.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the model-----------------')
    model.load_weights(checkpoint_save_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)

#训练模型
history = model.fit(x_train, y_train, batch_size=128, epochs=20, validation_data=(x_test, y_test), validation_freq=1,
                    callbacks=[cp_callback])   #把batch_size从16调到128,加快收敛
model.summary()

print(model.trainable_variables)
# 保存权重(所有可训练的参数)
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
    file.write(str(v.name) + '\n')
    file.write(str(v.shape) + '\n')
    file.write(str(v.numpy()) + '\n')
file.close()

###############################################    show   ###############################################

# 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值