欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TensorFlow深度学习(二)——图像分类

程序员文章站 2022-04-08 15:55:48
...

本文是书籍《TensorFlow深度学习》的学习笔记之一

理论部分

手写数字图片集

模型的泛化能力是指模型在新样本上也有良好的表现。为了提高泛化能力,我们应该尽量增加数据集的规模和多样性,使得我们用于学习的训练数据集和真实的手写数字图片的分布逼近,例如每个人手写数字都有不同的习惯,应该尽可能财经不同书写风格的图片。

TensorFlow深度学习(二)——图像分类
下面我们来看看图片的表示方法:
一张图片通常有h行,w列,每个点保存了像素值,像素值一般用整型数值来表达杨色强度:

  • 彩色图片:使用一维的,长度为3的向量来保存R、G、B值
  • 灰度图片:只需要一个数值表示强度,如0表示纯黑,255表示纯白,如下图
    TensorFlow深度学习(二)——图像分类

考虑输入格式,一张灰度图片使用矩阵的方式存储,形状为h行w列,b张图片使用[b,h,w]的张量存储,然后将矩阵打平为向量。
考虑输出格式,使用one-hot编码:如果物体属于第i类的话,将索引为i的位置设置1,其他位置设置0,如图:

TensorFlow深度学习(二)——图像分类

由于数字之间存在天然的大小关系,但优点是方便存储,所以一般存储时候使用数字编码,计算时候使用tf.one_hot()转换为比较稀疏的one-hot编码

误差计算

在分类问题中,更多的是采样交叉熵(Cross Entropy)损失函数,较少采用回归问题的MSE。损失函数可以定义为:
TensorFlow深度学习(二)——图像分类
模型训练的目标是优化:
TensorFlow深度学习(二)——图像分类
这里o=Wx+bo=Wx+b

非线性模型

线性模型的表达能力偏弱,用二次多项式就能学到更合适的模型
TensorFlow深度学习(二)——图像分类
我们可以使用一个**函数将线性模型转换为非线性模型,如Sigmoid函数、ReLU函数,我们的目标函数变为
o=ReLU(Wx+b)o=ReLU(Wx+b)

实验部分

模型搭建

# 利用sequential容器封装3个网络层,前一层的输入作为下一层的输出
model = keras.Sequential([
    # 创建一层网络,设置输出节点数为256,**函数为ReLU
    layer.Dense(256, activition - 'relu'),
    layer.Dense(128, activition - 'relu'),
    layer.Dense(10)
])

完整代码

链接

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

# 设置GPU使用方式
# 获取GPU列表
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
    try:
        # 设置GPU为增长式占用
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
    except RuntimeError as e:
        # 打印异常
        print(e)

(xs, ys), _ = datasets.mnist.load_data()
print('datasets:', xs.shape, ys.shape, xs.min(), xs.max())

batch_size = 32

xs = tf.convert_to_tensor(xs, dtype=tf.float32) / 255.
db = tf.data.Dataset.from_tensor_slices((xs, ys))
db = db.batch(batch_size).repeat(30)

model = Sequential([layers.Dense(256, activation='relu'),
                    layers.Dense(128, activation='relu'),
                    layers.Dense(10)])
model.build(input_shape=(4, 28 * 28))
model.summary()

optimizer = optimizers.SGD(lr=0.01)
acc_meter = metrics.Accuracy()

for step, (x, y) in enumerate(db):

    with tf.GradientTape() as tape:
        # 打平操作,[b, 28, 28] => [b, 784]
        x = tf.reshape(x, (-1, 28 * 28))
        # Step1. 得到模型输出output [b, 784] => [b, 10]
        out = model(x)
        # [b] => [b, 10]
        y_onehot = tf.one_hot(y, depth=10)
        # 计算差的平方和,[b, 10]
        loss = tf.square(out - y_onehot)
        # 计算每个样本的平均误差,[b]
        loss = tf.reduce_sum(loss) / x.shape[0]

    acc_meter.update_state(tf.argmax(out, axis=1), y)

    grads = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    if step % 200 == 0:
        print(step, 'loss:', float(loss), 'acc:', acc_meter.result().numpy())
        acc_meter.reset_states()

实验结果

TensorFlow深度学习(二)——图像分类
TensorFlow深度学习(二)——图像分类
TensorFlow深度学习(二)——图像分类

总结

本实验使用了3层的非线性神经网络进行图像分类,表达能力比单层的线性回归模型更强。通过逐层的梯度下降来更新参数,使用tensorflow非常方便,最后效果也很好,初步感受了深度学习、tensorflow的强大之处。