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