使用ResNet网络对Cifar-100数据集分类

ResNet

导入

import tensorflow.keras as keras
import tensorflow as tf
from tensorflow.keras import layers, Sequential

basic block

class BasicBlock(layers.Layer):

    def __init__(self, kernel_num, stride=1):
        super(BasicBlock, self).__init__()

        # 第一层3*3卷积网络
        self.conv1 = layers.Conv2D(kernel_num, (3, 3), strides=stride, padding='same')
        self.bin1 = layers.BatchNormalization()
        self.relu = layers.Activation('relu')

        # 第二层3*3卷积网络
        self.conv2 = layers.Conv2D(kernel_num, (3, 3), strides=1, padding='same')
        self.bin2 = layers.BatchNormalization()
        # 将input数据做处理,如果上面卷积结果没有降维,就不做下采样 else中的内容
        # 如果降维了就做下采样 if中的内容
        if stride != 1:
            self.downSample = Sequential()
            self.downSample.add(layers.Conv2D(kernel_num, (1, 1), strides=stride))
            # using kernel size (1,1) is not same with pooling opration
            # target is that reshape input add convolution output legitlegitimate
        else:
            self.downSample = lambda x: x

    def call(self, inputs, training=None):
        # b,h,w,c
        conv1 = self.conv1(inputs)
        bn1 = self.bin1(conv1)
        relu1 = self.relu(bn1)
        conv2 = self.conv2(relu1)
        bn2 = self.bin2(conv2)

        residual = self.downSample(inputs)

        output = layers.add([residual, bn2])
        output = tf.nn.relu(output)
        return output

resnet block

class ResNet(keras.Model):

 def __init__(self, layers_dims, num_class=100):  # layers_dims#[2,2,2,2]
     super(ResNet, self).__init__()

     self.stem = Sequential([
         layers.Conv2D(64, kernel_size=(3, 3), strides=(1, 1)),
         layers.BatchNormalization(),
         layers.Activation('relu'),
         layers.MaxPool2D(pool_size=(2, 2), strides=(1, 1), padding='same')
     ])
     self.layer1 = self.build_resblock(64, layers_dims[0])
     self.layer2 = self.build_resblock(128, layers_dims[1], stride=2)
     self.layer3 = self.build_resblock(256, layers_dims[2], stride=2)
     self.layer4 = self.build_resblock(512, layers_dims[3], stride=2)
     # feature size will sucessive reduce

     # output:[b,512,h(unknown),w(unknown)]=>GlobalAveragePooling2D()=>[b,512]
     self.avgpool = layers.GlobalAveragePooling2D()
     self.fc = layers.Dense(num_class)

 def call(self, inputs, training=None):
     x = self.stem(inputs)

     x = self.layer1(x)
     x = self.layer2(x)
     x = self.layer3(x)
     x = self.layer4(x)

     x = self.avgpool(x)
     x = self.fc(x)

     return x

 def build_resblock(self, kernel_num, blocks, stride=1):
     res_blocks = Sequential()

     res_blocks.add(BasicBlock(kernel_num, stride))
     for _ in range(1, blocks):
         res_blocks.add(BasicBlock(kernel_num, stride=1))

     return res_blocks

ResNet18和ResNet34

def ResNet18():
 return ResNet([2, 2, 2, 2], num_class=100)


def ResNet34():
 return ResNet([3, 4, 6, 3], num_class=100)

训练及损失和准确率可视化

ResNet18

import tensorflow as tf
from ResNet import ResNet18
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot as plt


# 数据预处理
def preprocess(x, y):
   x = 2 * tf.cast(x, dtype=tf.float32) / 255. - 1
   y = tf.cast(y, dtype=tf.int32)
   return x, y


(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.cifar100.load_data()
train_images, test_images = preprocess(train_images, test_images)

test_dataset = tf.data.Dataset.from_tensor_slices((test_images, test_labels))
test_dataset = test_dataset.map(preprocess).batch(200)

validation_images = train_images[45000:]
train_images = train_images[0:45000]
validation_labels = train_labels[45000:]
train_labels = train_labels[0:45000]

datagen = ImageDataGenerator(
   featurewise_center=False,  # 布尔值。将输入数据的均值设置为 0,逐特征进行。
   samplewise_center=False,  # 布尔值。将每个样本的均值设置为 0。
   featurewise_std_normalization=False,  # 布尔值。将输入除以数据标准差,逐特征进行。
   samplewise_std_normalization=False,  # 布尔值。将每个输入除以其标准差。
   zca_whitening=False,  # 布尔值。是否应用 ZCA 白化。
   # zca_epsilon  ZCA 白化的 epsilon 值,默认为 1e-6。
   # rotation_range=30,  # 整数。随机旋转的度数范围 (degrees, 0 to 180)
   width_shift_range=0.2,  # randomly shift images horizontally (fraction of total width)
   height_shift_range=0.2,  # randomly shift images vertically (fraction of total height)
   horizontal_flip=True,  # 布尔值。随机水平翻转。
   vertical_flip=False,  # 布尔值。随机垂直翻转
   fill_mode='nearest'
)

datagen.fit(train_images)


# 用于计算多分类问题的交叉熵
def spareCE(y_true, y_pred):
   sce = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
   # 参数from_logits=False表示输出的logits需要经过激活函数的处理,默认为False
   return tf.reduce_mean(sce(y_true, y_pred))


# 正则化
def l2_loss(my_model, weights=1e-4):
   variable_list = []
   for v in my_model.trainable_variables:
       if 'kernel' or 'bias' in v.name:
           variable_list.append(tf.nn.l2_loss(v))
   return tf.add_n(variable_list) * weights


# 损失函数
def myLoss(y_true, y_pred):
   sce = spareCE(y_true, y_pred)
   l2 = l2_loss(my_model=model)
   loss = sce + l2
   return loss


model = ResNet18()
model.compile(
   optimizer=tf.keras.optimizers.Adam(learning_rate=0.001, decay=0.004),
   loss=myLoss,
   metrics=['sparse_categorical_accuracy'])
# model.compile()具体使用查看https://blog.csdn.net/huang1024rui/article/details/120055487
history = model.fit(
   datagen.flow(train_images, train_labels, batch_size=64), steps_per_epoch=len(train_images) / 64,
   epochs=100, verbose=2,
   validation_data=(validation_images, validation_labels)
)
model.save('saved_model/ResNet18')
my_model = tf.keras.models.load_model('saved_model/ResNet18', custom_objects={'myLoss': myLoss})

correct = 0
total = 0
for x, y in test_dataset:
   y_pred = my_model(x, training=False)
   y_pred = tf.cast(tf.argmax(y_pred, 1), dtype=tf.int32)
   y_true = tf.cast(tf.squeeze(y, -1), dtype=tf.int32)
   equality = tf.equal(y_pred, y_true)
   equality = tf.cast(equality, dtype=tf.float32)
   correct += tf.reduce_sum(equality)
   total += x.shape[0]
   print(float(correct) / total)
print('Accuracy=', float(correct) / total)


fig1, ax_acc = plt.subplots()
plt.plot(history.history['sparse_categorical_accuracy'], 'r', label='acc')
plt.plot(history.history['val_sparse_categorical_accuracy'], 'b', label='val_acc')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Model - Accuracy')
plt.legend(loc='lower right')
plt.savefig('./picture/ResNet18_acc.png')
plt.show()

fig2, ax_loss = plt.subplots()
plt.plot(history.history['loss'], 'r', label='loss')
plt.plot(history.history['val_loss'], 'b', label='val_loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Model- Loss')
plt.legend(loc='upper right')
plt.savefig('./picture/ResNet18_loss.png')
plt.show()

准确率

 Accuracy= 0.6133

损失和准确率的变化图

ResNet34

import tensorflow as tf
from ResNet import ResNet34
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot as plt


# 数据预处理
def preprocess(x, y):
    x = 2 * tf.cast(x, dtype=tf.float32) / 255. - 1
    y = tf.cast(y, dtype=tf.int32)
    return x, y


(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.cifar100.load_data()
train_images, test_images = preprocess(train_images, test_images)

test_dataset = tf.data.Dataset.from_tensor_slices((test_images, test_labels))
test_dataset = test_dataset.map(preprocess).batch(200)

validation_images = train_images[45000:]
train_images = train_images[0:45000]
validation_labels = train_labels[45000:]
train_labels = train_labels[0:45000]

datagen = ImageDataGenerator(
    featurewise_center=False,
    samplewise_center=False,
    featurewise_std_normalization=False,
    samplewise_std_normalization=False,
    zca_whitening=False,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    vertical_flip=False,
    fill_mode='nearest'
)

datagen.fit(train_images)


def spareCE(y_true, y_pred):
    sce = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
    return tf.reduce_mean(sce(y_true, y_pred))


def l2_loss(my_model, weights=1e-4):
    variable_list = []
    for v in my_model.trainable_variables:
        if 'kernel' or 'bias' in v.name:
            variable_list.append(tf.nn.l2_loss(v))
    return tf.add_n(variable_list) * weights


def myLoss(y_true, y_pred):
    sce = spareCE(y_true, y_pred)
    l2 = l2_loss(my_model=model)
    loss = sce + l2
    return loss


model = ResNet34()
model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001, decay=0.004),
    loss=myLoss,
    metrics=['sparse_categorical_accuracy'])
history = model.fit(
    datagen.flow(train_images, train_labels, batch_size=64), steps_per_epoch=len(train_images) / 64,
    epochs=100, verbose=2,
    validation_data=(validation_images, validation_labels)
)
model.save('saved_model/ResNet34')
my_model = tf.keras.models.load_model('saved_model/ResNet34', custom_objects={'myLoss': myLoss})

correct = 0
total = 0
for x, y in test_dataset:
    y_pred = my_model(x, training=False)
    y_pred = tf.cast(tf.argmax(y_pred, 1), dtype=tf.int32)
    y_true = tf.cast(tf.squeeze(y, -1), dtype=tf.int32)
    equality = tf.equal(y_pred, y_true)
    equality = tf.cast(equality, dtype=tf.float32)
    correct += tf.reduce_sum(equality)
    total += x.shape[0]
    print(float(correct) / total)
print('Accuracy=', float(correct) / total)


fig1, ax_acc = plt.subplots()
plt.plot(history.history['sparse_categorical_accuracy'], 'r', label='acc')
plt.plot(history.history['val_sparse_categorical_accuracy'], 'b', label='val_acc')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Model - Accuracy')
plt.legend(loc='lower right')
plt.savefig('./picture/ResNet34_acc.png')
plt.show()

fig2, ax_loss = plt.subplots()
plt.plot(history.history['loss'], 'r', label='loss')
plt.plot(history.history['val_loss'], 'b', label='val_loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Model- Loss')
plt.legend(loc='upper right')
plt.savefig('./picture/ResNet34_loss.png')
plt.show()

准确率

Accuracy= 0.6048

损失和准确率的变化图

cifar-100数据集可视化

在这里插入图片描述

改进

将epochs从50改为100,ResNet34准确率从 0.6016变为 0.6048,而150时准确率为0.6022

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值