这里根据keras提供的cifar100的数据集做一个实战案例的回顾
CIFAR100是一个有100个类别的图片数据集,其体量比CIFAR10大了不是一点点,那么我们要如何更好的处理这样大批量的数据集呢,这里使用卷积神经网络进行解决
其网络结构如下图:
上代码
import tensorflow as tf
from tensorflow.keras import layers, optimizers, datasets, Sequential
import os
os.environ['TP_CPP_MIN_LOG_LEVEL'] = '2'
tf.random.set_seed(2345)
#这里使用的是Sequential结构来构建网络,我们先通过调用keras里边的layers进行
#构建一个layers的网络架构,这里构建的是一个5层的卷积神经网络
conv_layers = [
# unit 1
layers.Conv2D(64, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.Conv2D(64, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.MaxPool2D(pool_size = [2,2], strides = 2, padding = 'same'),
#卷积网络一般是由两个卷积层和一个池化采样层组合构成的,这里kernel size同一位3*3,池化采样的pool size则为2*2
# unit 2 这里第一个参数128是指这个卷积层输出数据的纬度,即卷积核的个数-》batch,其与输出的通道数是一样的
#可以看到我们的通道数从3变化为了64 -》 128 -》 256 -》 512
layers.Conv2D(128, kernel_size = [3,3], padding = 'same',activation= tf.nn.relu),
layers.Conv2D(128, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.MaxPool2D(pool_size=[2,2], strides = 2, padding = 'same'),
# unit 3
layers.Conv2D(256, kernel_size = [3,3], padding = 'same',activation= tf.nn.relu),
layers.Conv2D(256, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.MaxPool2D(pool_size=[2,2], strides = 2, padding = 'same'),
# unit 4
layers.Conv2D(512, kernel_size = [3,3], padding = 'same',activation= tf.nn.relu),
layers.Conv2D(512, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.MaxPool2D(pool_size=[2,2], strides = 2, padding = 'same'),
# unit 5
layers.Conv2D(512, kernel_size = [3,3], padding = 'same',activation= tf.nn.relu),
layers.Conv2D(512, kernel_size = [3,3], padding = 'same', activation = tf.nn.relu),
layers.MaxPool2D(pool_size=[2,2], strides = 2, padding = 'same'),
]
def preprocess(x, y):
x = tf.cast(x, dtype = tf.float32) / 255.
y = tf.cast(y, dtype = tf.int32)
return x, y
#尝龟的归一化操作
(x, y), (x_test, y_test) = datasets.cifar100.load_data()
#读入数据
y = tf.squeeze(y, axis = 1)
#把label去掉第二个维度,只留下一个维度作为标签
y_test = tf.squeeze(y_test, axis = 1)
print(x.shape, y.shape, x_test.shape, y_test.shape)
train_db = tf.data.Dataset.from_tensor_slices((x, y))
#将数据转换为tensor形式的张量
train_db = train_db.shuffle(1000).map(preprocess).batch(128)
#打乱数据集,并进行预处理,划分为128个为一组的batch
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.amp(preprocess).batch(64)
#作为测试集我们就不需要打乱了
sample = next(iter(train_db))
#合理通过next(iter())创建一个可以迭代的对象sample
print('sample:', sample[0].shape, sample[1].shape,
tf.reduce_min(sample[0]), tf.reduce_max(sample[0]))
def main():
conv_net = Sequential(conv_layers)
#通过之前的list构建卷积网络,下面这个是同理构建全连接层的
fc_net = Sequential([
layers.Dense(256,activation = tf.nn.relu),
layers.Dense(128, activation = tf.nn.relu),
layers.Dense(100, activation = None),
])
#这里我们使用build方法构建对应网络结构,输入第一个为none时表示我们输入的图像个数适应于数据集
#而其原始维度是32*32 通道数为3
conv_net.build(input_shape = [None, 32, 32, 3])
fc_net.build(input_shape= [None, 512])
#这里因为最后一个卷积层输出的通道数为512所以全连接层通道数参数为512
#[b, 32, 32, 3] => [b, 1, 1, 512]
optimizer = optimizers.Adam(lr = 1e-4)
#使用Adam 优化器 学习率设置为1e-4
# 梯度下降的求梯度我们需要把卷积核全连接的参数汇总到一块
variables = conv_net.trainable_variables + fc_net.trainable_variables
for epoch in range(50):
for step, (x, y) in enumerate(train_db):
with tf.GradientTape() as tape:
"""[b, 32, 32, 3] => [b, 1, 1, 512]"""
#将原始输入的 32 * 32 转变为全连接层的 1*1 512
out = conv_net(x)
# flatten打平512的操作
out = tf.reshape(out, [-1, 512])
# 这里是100分类问题所以我们还需要将512通道的数据转换为b,100维的数据进行loss计算
logits = fc_net(out)
# [b] => [b, 100] 这里引入onehot将原始标签进行独热编码
y_onehot = tf.one_hot(y, depth = 100)
#计算损失函数值
loss = tf.losses.categorical_crossentropy(y_onehot, logits, from_logits = True)
loss = tf.reduce_mean(loss)
grads = tape.gradient(loss, variables)
optimizer.apply_gradients(zip(grads, variables))
if step % 100 == 0:
print(epoch, step, 'loss', float(loss))
total_num = 0
total_correct = 0
for x,y in test_db:
out = conv_net(x)
out = tf.reshape(out, [-1,512])
#-1表示不用指定通过后面的512来限定计算这个维度
logits = fc_net(out)
prob = tf.nn.softmax(logits, axis = 1)
#将输出进行softmax激活函数映射为0-1之间的值
pred = tf.argmax(prob, axis = 1)
pred = tf.cast(pred, dtype = tf.int32)
correct = tf.cast(tf.equal(pred, y), dtype = tf.int32)
correct = tf.reduce_sum(correct)
total_num += x.shape[0]
total_correct += int(correct)
acc = total_correct / total_num
print(epoch, 'acc:', acc)
if __name__ == '__main__':
main()