分类问题

1 导入模型库

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from    tensorflow import keras
from    tensorflow.keras import layers, optimizers, datasets

2 数据集

2.1加载数据

(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()

load_data()函数返回两个元组(tuple)对象,第一个是训练集,第二个是测试集,每个 tuple的第一个元素是多个训练图片数据x_train, 第二个元素是训练图片对应的类别数字y_train,第三个元素是多个测试图片数据x_val, 第四个元素是测试图片对应的类别数字y_test.

print(x_train.shape, y_train.shape)
#输出:(60000, 28, 28), (60000, 10)

其中训练集x_train的大小为(60000,28,28),代表了 60000 个样本,每个样本由 28 行、 28 列构成,由于是灰度图片,故没有 RGB 通道; 训练集x_train的大小为(60000, ),代表了这 60000 个样本的标签
数字,每个样本标签用一个 0~9 的数字表示。测试集 x_test的大小为(10000,28,28),代表了
10000 张测试图片, y_test的大小为(10000,)

print(x_train[0])#打印第一张图片
print(y_train[0])#打印第一张图片的标签
#x_train[0] 输出
 [[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0   0   0 0   0   0   0   0   0   0   0  0  0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0   0   0 0   0   0   0   0   0   0   0  0  0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0   0   0 0   0   0   0   0   0   0   0   0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0   0   0 0   0   0   0   0   0   0   0   0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0   0   0 0   0   0   0   0   0   0   0   0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 3 18 18 18 126 136 175  26 166 255 247 127 0  0  0 0]
 [ 0 0 0 0 0 0 0 30 36 94 154 170 253 253 253 253 253 225 172 253 242 195 64  0]
 [ 0 0 0 0 0 0 49 238 253 253 253 253 253 253 253 253 251 93 82 82 56 39 0  0 0]
 [ 0 0 0 0 0 0 0 18 219 253 253 253 253 253 198 182 247 241 0 0 0 0 0 0 0 0 0 0]
 [ 0 0 0 0 0 0 0 0 80 156 107 253 253 205 11 0 43 154 0 0 0 0 0 0 0 0  0  0]
 [ 0 0 0 0 0 0 0 0 0 14 1154 253 90 0  0  0  0 0  0  0  0  0  0   0  0  0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 139 253 190 2 0 0 0 0  0  0  0  0  0  0  0 0  0]
 [ 0  0  0 0 0 0 0 0 0 0  0  11 190 253  70   0  0   0 0  0    0  0  0 0 0  0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0 35 241 225 160 108 1 0 0 0  0   0   0   0   0  0  0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  0  81 240 253 253 119 25  0   0  0  0   0  0  0 0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  0   0  45 186 253 253 150  27 0 0   0   0  0  0  0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  0   0   0  16  93 252 253 187 0  0  0   0  0  0 0  0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  0   0   0   0   0 249 253 249  64   0  0  0 0 0  0 0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  0   0  46 130 183 253 253 207  2 0  0   0  0  0 0  0]
 [ 0 0 0 0 0 0 0 0 0 0 0 0  39 148 229 253 253 253 250 182 0 0  0   0  0  0  0 0]
 [ 0 0 0 0 0 0 0 0 0 0 24 114 221 253 253 253 253 201 78     0  0 0  0 0  0  0 0]
 [ 0 0 0 0 0 0 0 0 23  66 213 253 253 253 253 198  81 2 0 0 0 0 0  0  0  0   0 0]
 [ 0 0 0 0 0 0 18 171 219 253 253 253 253 195  80  9  0 0 0 0 0 0 0 0  0  0  0 0]
 [ 0 0 0 0 55 172 226 253 253 253 253 244 133 11 0 0 0 0 0 0 0  0 0 0  0  0  0 0]
 [ 0 0 0 0 136 253 253 253 212 135 132  16 0 0 0 0 0 0 0 0 0 0  0  0  0  0   0 0]
 [ 0 0 0 0 0 0  0  0   0   0   0   0   0   0 0 0 0 0 0 0 0 0    0  0  0  0   0 0]
 [ 0 0 0 0 0 0  0  0   0   0   0   0   0   0 0 0 0 0 0 0 0 0    0  0  0  0   0 0]
 [ 0 0 0 0 0 0  0  0   0   0   0   0   0   0 0 0 0 0 0 0 0 0    0  0  0  0   0 0]]
 #y_train[0] 输出
  5

我们看到图片的表示方法。 一张图片包含了ℎ行(Height/Row), 𝑤列(Width/Column),每个位置保存了像素(Pixel)值,像素值一般使用 0~255 的整形数值来表达颜色强度信息, 例如 0 表示强度最低, 255 表示强度最高。如果是彩色图片, 则每个像素点包含了 R、 G、 B 三个通道的强度信息, 分别代表红色通道、绿色通道、蓝色通道的颜色强度, 所以与灰度图片不同,它的每个像素点使用一个 1 维、长度为 3 的向量(Vector)来表示,向量的 3 个元素依次代表了当前像素点上面的 R、 G、 B 颜色强值,因此彩色图片需要保存为形状是[ℎ, 𝑤, 3]的张量(Tensor,可以通俗地理解为 3 维数组)。 如果是灰度图片, 则使用一个数值来表示灰度强度,例如 0 表示纯黑, 255 表示纯白,因此它只需要一个形状为[ℎ, 𝑤]的二维矩阵(Matrix)来表示一张图片信息(也可以保存为[ℎ, 𝑤, 1]形状的张量)。 上面没演示了内容为 5 的数字图片的矩阵内容,可以看到,图片中黑色的像素用 0 表
示,灰度信息用 0~255 表示,图片中灰度越白的像素点,对应矩阵位置中数值也就越大。

2.2 数据处理

由于此图片分类已经是比较成熟的分类问题处理了,因此不需要数据清洗,特征处理了,只需要进行简单的数据转换, 在机器学习中间,一般希望数据的范围在 0 周围小范围内分布。通过预处理步骤,我们把[0,255]像素范
围归一化(Normalize)到[0,1. ]区间, 再缩放到[-1,1]区间, 从而有利于模型的训练 。

x_train = tf.convert_to_tensor(x_train, dtype=tf.float32) / 255.
y_train = tf.convert_to_tensor(y_train, dtype=tf.int32)
y_train = tf.one_hot(y_train, depth=10) #one_hot编码

2.3 查看图片数据处理后的值

print(x_train[0])
print(y_train[0])
#x_train[0],如同在没有进行归一化之前是一样的,只是将数字从0-255变成了0-1之间
#y_train[0] 输出
tf.Tensor([0. 0. 0. 0. 0. 1. 0. 0. 0. 0.], shape=(10,), dtype=float32)

3 批量数据对象构建

train_dataset = tf.data.Dataset.from_tensor_slices((x, y)) # 构建数据集对象
train_dataset = train_dataset.batch(512) # 批量训练

每一张图片的计算流程是通用的,我们在计算的过程中可以一次进行多张图片的计算, 充分利用 CPU 或 GPU 的并行计算能力。 一张图片我们用 shape 为[h, w]的矩阵来表示, 对于多张图片来说,我们在前面添加一个数量维度(Dimension),使用 shape 为[𝑏, ℎ, 𝑤]的张量来表示, 其中的𝑏代表了 batch size(批量);多张彩色图片可以使用 shape 为[𝑏, ℎ, 𝑤, 𝑐]的张量来表示,其中的𝑐表示通道数量(Channel),彩色图片𝑐 = 3。 通过 TensorFlow 的Dataset 对象可以方便完成模型的批量训练,只需要调用 batch()函数即可构建带 batch 功能的数据集对象 。

4 网络模型搭建

4.1网络框架

​ 三层神经网络模型

medol = keras.Sequential([
    layers.Dense(512,activation='relu'),
    layers.Dense(256,activation='relu'),
    layers.Dense(10)])

4.2 网络计算表达式

x = tf.reshape(x, (-1, 28 * 28))

由于图片是28x28,要满足y=wx+b,因此要将其形状改变一下

4.3 误差计算函数

4.31 均方差

loss = tf.reduce_sum(tf.square(out - y)) / x.shape[0])

4.32 交叉熵

loss = tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=y)

交叉熵的完整介绍和分析: https://blog.csdn.net/tsyccnh/article/details/79163834

4.4 梯度更新

利用 TensorFlow 提供的自动求导函数 tape.gradient(loss, model.trainable_variables)求出模
型中所有的梯度信息𝜕ℒ/𝜕𝜃 , 𝜃 ∈ {𝑊1, 𝒃𝟏, 𝑊2, 𝒃𝟐, 𝑊3, 𝒃𝟑}:

with tf.GradientTape() as tape
#compute 𝑊1, 𝒃𝟏, 𝑊2, 𝒃𝟐, 𝑊3, 𝒃𝟑
grads = tape.gradient(loss,model.trainable_variables)
#update w' = w-lr*grad
optimizer.apply_gradients(zip(grads,model.trainable_variables))

4.5 优化函数

optimizer = optimizers.SGD(learning_rate=0.001)

各种优化函数介绍:https://blog.csdn.net/qq_21460525/article/details/70146665

简单总结:

BGD: 遍历所有的训练数据,更新一次参数

MBGD:遍历一批训练数据,更新一次参数

SGD:遍历每一条训练数据,更新一次参数

4.6 完整代码

model = keras.Sequential([
    layers.Dense(512, activation='relu'),
    layers.Dense(256, activation='relu'),
    layers.Dense(10)])

optimizer = optimizers.SGD(learning_rate=0.001)

def train_epoch(epoch):
    # Step4.loop
    for step, (x, y) in enumerate(train_dataset):
        with tf.GradientTape() as tape:
            # [b, 28, 28] => [b, 784]
            x = tf.reshape(x, (-1, 28 * 28))
            # Step1. compute output
            # [b, 784] => [b, 10]
            out = model(x)
            # Step2. compute loss
            loss = tf.reduce_sum(tf.square(out - y)) / x.shape[0]
            #loss = tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=y)
        # Step3. optimize and update w1, w2, w3, b1, b2, b3
        grads = tape.gradient(loss, model.trainable_variables)
        # w' = w - lr * grad
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
        if step % 100 == 0:
            print(epoch, step, 'loss:', loss.numpy())

5 训练

def train():
    for epoch in range(30):
        train_epoch(epoch)

6 测试

6.1 评价函数

待补充


posted @ 2020-03-01 15:03  Arrkwin  阅读(363)  评论(0)    收藏  举报