最近在学习tf2.0 这是一个使用cifar100数据集做训练的实战代码,其中本人做了详细注释,主要是做下总结记录,感觉还是挺详细的。大家有想要教程的可以联系我。微信:13623323579.

import os
import tensorflow as tf
from tensorflow.keras import layers, optimizers, datasets, Sequential

os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
tf.random.set_seed(2345)


conv_layers = [ # 5 units of conv + maxpooling    一般来说 让h 和 w 慢慢缩小,channel会慢慢增大,即位置信息逐渐消失,每个像素包含的信息量逐渐增加,把一些高层概念放到一个相应的单元中。
    # unit1   64: channel数量   kernel_size:卷积核大小  padding='same':自动填充 activation:激活函数
    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'),

    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'),

    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'),

    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'),

    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转化到[0,1] 之间  y转化为int类型
    x = tf.cast(x, dtype=tf.float32) / 255.
    y = tf.cast(y, dtype=tf.int32)

    return x, y

# 加载cifar100数据 如果本地没有,会自动下载。
(x, y), (x_test, y_test) = datasets.cifar100.load_data()
# print(x.shape, y.shape, x_test.shape, y_test.shape)
# 形状:(50000, 32, 32, 3) (50000, 1)这里要注意,y的形状,后面要去掉为1的维度  (10000, 32, 32, 3) (10000, 1)

y = tf.squeeze(y, axis=1)           # 去掉为1 的维度 [50000, 1] => [5000]
y_test = tf.squeeze(y_test, axis=1) # 去掉为1 的维度 [50000, 1] => [5000]

# 加载数据集
train_db = tf.data.Dataset.from_tensor_slices((x, y))
# 对数据的处理       打乱数据        批预处理         设置batch大小
train_db = train_db.shuffle(10000).map(preprocess).batch(64)

test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.map(preprocess).batch(64)

# 这里只是为了查看数据形状,在整个程序中并无意义
sample = next(iter(train_db))
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)

    # 此处是为了测试卷积网络,看输出数据形状
    # x = tf.random.normal([4, 32, 32, 3])
    # out = conv_net(x)
    # print(out.shape)

    # 构建全连接网络
    fc_net = Sequential([
        layers.Dense(256, activation=tf.nn.relu),
        layers.Dense(128, activation=tf.nn.relu),
        layers.Dense(100, activation=None)
    ])

    # build()
    conv_net.build(input_shape=[None, 32, 32, 3])
    fc_net.build(input_shape=[None, 512])

    # 优化器:Adam
    optimizer = optimizers.Adam(lr=1e-4)

    # variables: 卷积网络和全连接网络的所有参数
    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: 中,方便计算梯度
            with tf.GradientTape() as tape:
                # 数据进入卷积网络[64, 32, 32, 3] => [64, 1,1, 512]
                out = conv_net(x)
                # 变形[64, 1,1, 512] => [b, 512]
                out = tf.reshape(out, [-1, 512])
                # 数据进入全连接层[b, 512] => [b, 100]
                logits = fc_net(out)
                # 对y做one_hot处理 [b] => [b, 100]
                y_one_hot = tf.one_hot(y, depth=100)
                # 计算损失函数     交叉熵损失函数        one_hot之后的y  输出结果  这里要设置为True
                loss = tf.losses.categorical_crossentropy(y_one_hot, logits, from_logits=True)
                loss = tf.reduce_mean(loss)

            # 计算梯度  variables:所有变量
            grads = tape.gradient(loss, variables)
            # 反向传播计算 grads 要和 变量一一对应,所以用zip
            optimizer.apply_gradients(zip(grads, variables))

            if step % 100 == 0:
                print(epoch, step, "loss:", float(loss))


        # 以下是测试部分--
        # 测试流程:
        # 1、数据放入网络得到数据。
        # 2、 softmax得到概率。
        # 3、 argmax 得到最大值的位置。
        # 4、equal 与最大值比较, 得到True False。 cast转化为int格式(0, 1)
        # 5、reduce_sum 计算预测正确的数量
        # 6、计算总的预测正确的数量(每个batch预测正确的相加) 和 总的数据数量(每个batch的总数量)
        # 7、计算准确率 acc
        total_num = 0
        total_correct = 0
        for x, y in test_db:

            # 数据放入网络,得到输出 [b, 100]
            out = conv_net(x)
            out = tf.reshape(out, [-1, 512])
            logits = fc_net(out)

            # softmax 处理 每个数据处理成概率
            prob = tf.nn.softmax(logits, axis=1)
            # argmax 返回指定维度的最大值的位置 int64类型
            pred = tf.argmax(prob, axis=1)
            # 转化数据格式 int64 -> int32
            pred = tf.cast(pred, dtype=tf.int32)

            # tf.cast:把true False转化成 int格式:0或者1   tf.equal: 比较预测值和真实值,结果是True或者False
            correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
            # 计算所有正确的总数(在上一步,预测正确的已经转化为1)
            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()
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐