分类问题
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 评价函数
待补充

浙公网安备 33010602011771号