Char3-分类问题
在人工智能上花一年时间,这足以让人相信上帝的存————艾伦佩利
分类问题典型的应用就是教会机器如何去自动识别图片中物体的种类。本章中主要是介绍了MNIST
数据集。
手写数字数据集介绍
数据集是手写数字0-9
,具有的特征为:
-
真人书写的
0-9
数字图片 -
为了便于存储和计算,将图片缩放到固定的大小
size
,比如224*224,或者96*96:作为输入x
-
每张图片加上标签
label
,作为图片的真实值y
-
一般是通过映射方式进行类别命名;通过
0-1
表示正反面的方式,叫做数字编码。
MNIST数据集具体信息
特征
-
包含0-9共10中数字的手写图片,每种数字7000张,总共70000张
-
60000张是属于训练集,剩下的属于测试集
-
每张图片缩放到28*28的大小
-
图片是真人书写,包含了:字体大小、书写风格、粗细等丰富的样式

每张图片信息
-
每张图片包含h行(height、row)和w(width、column)列
-
每个位置保存了
pixel
像素值,像素值使用的是0-255
来表示强度值,0
表示最低,`255表示最高 -
如果是彩色图片,每个图片包含RGB三通道,分别是红色、绿色、黄色的颜色强度。保存的形状是[h,w,3]的张量Tensor,即3维数组
-
如果是灰色照片,像素点就是一个1维、长度为3的向量;使用形状为
[h,w]
的二维数组来表示一张图片信息,也可以表示成[h,w,1]
形状的张量

利用TF下载MNIST数据
- 导入各种子库
- 加载数据集
- 将数据转成张量形式
- 将输出y转换成
one-hot
编码形式 - 构建数据集对象和批量训练
import os
import tensorflow as
from tensorflow import kreas # 导入子库
from tensorflow.kreas import layers, optimizers, datasets
(x,y), (x_val, y_val) = datasets.mnist.load_data() # 加载数据集
x = 2 * tf.convert_to_tensor(x, dtype=tf.float32) / 255.-1 # 转成张量,并且缩放到-1到1之间
y = tf.convert_to_tensor(y, dtype=tf.int32) # 转成张量
y = tf.one_hot(y, depth=10) # 热编码形式
print(x.shape, y_shape)
train_dataset = tf.data.Dataset.from_tensor_slices(x,y) # 构建数据集对象
train_dataset = train_data.batch(512) # 批量训练
代码的具体解释:
-
load_data()
函数:返回的是两个元组对象:训练集+测试集;每个元组的第一个元素是多个训练图片数据训练集数据X,第二个元素是训练图片对应的类别数字Y -
训练集X大小是(60000,28,28),灰色照片,没有RGB通道
-
训练集Y大小是(60000),代表的是标签,每个标签用一个0-9的数字表示
-
测试集X的大小是(10000,28,28),10000张测试图片,Y的大小是(10000,),也是标签
图片表示方法
-
一张图片用shape为[h,w]的矩阵来表示;
-
多张图片前面加上维度
dimension
,使用shape
为[b,h,w]的张量来表示,其中b表示batch size(批量) -
多张彩色图片使用
shape
为[b,h,w,c]表示,c表示的是通道数量channel,彩色图片c=3
调用batch()函数即可构建带batch功能的数据集对象
模型构建
向量形式的生成
-
回归模型中,一组长度为
的输入向量
简化为
,表达式为
-
多输入、单输出的模型结构,借助向量形式
Qp03kD.png
-
多输出节点、批量训练方式,模型写成张量形式
其中
,
,
-
表示输入节点数目
-
表示输出节点数目
-
X的形状shape为
,表示b个样本的输入,每个样本的特征长度
-
的shape为
,包含
个网络参数
-
偏置向量
的shape为
,每个输出节点上允许添加一个偏置值
-
符号表示的是矩阵相乘


对应模型为:

中的上标表示样本索引号(表示第几个样本),下标表示样本向量的元素(样本的第几个特征)
图片识别任务转成张量形式
- 图片的输入格式
一张图片使用的是矩阵方式存储,shape为:[h,w];
b张图片使用shape为[b,h,w]的张量X进行存储
模型只接受向量形式的输入特征向量,需要将矩阵形式平铺成
的向量,输入特征的长度为

- 对于输出标签
数字编码的结果(比如1表示猫,2表示鱼,3表示狗)之间存在天然的大小关系。
解决方法
-
将输出设置为
个输出节点的向量,
与类别数相同
-
让第
个输出值表示当前样本属于类别i的概率P
-
如果属于第
类,索引为
的位置设置为1,其余为0!!!!
-
下图中:对于所有猫的图片,数字编码是0,
one-hot
编码为[1,0,0,0];其他类推

- 手写数字图片数据
总类别数是10,即输出节点总数值,假设某个样本的类别是i,即图片中的数字是,需要一个长度为10的向量,索引号为的位置设置为1,其余是0。
-
0的one-hot编码是[1,0,0,0,….]
-
1的one-hot编码是[0,1,0,0,….]
-
其余类推
One-hot编码是非常稀疏Sparse
的,占用的存储空间多,所以在存储的时候还是采用数字编码。
# 数字编码转成 one-hot 编码
y = tf.constant([0,1,2,3]) # 数字编码
y = tf.ont_hot(y, depth=10) # one-hot编码
关于手写数字图片:
-
输入是一张打平后的图像量
-
输出是长度为10的向量
-
真实标签
y
经过one-hot
变成长度为10的稀疏向量 -
多输入和多输出的线性预测模型是
,希望其更接近真实标签
y
误差计算
对于分类问题,目标是优化某个性能指标,比如准确度acc。常用的做法是设立一个平滑可导的代理目标函数:模型输出和真实标签
之间的距离。
通过优化损失函数来找到最优解,采用的是交叉熵cross entropy
损失函数
1. 存在的问题:
- 欠拟合(左图):线性模型,表达能力差
- 过拟合(右图):模型过于复杂,表达能力过强,伤害模型的泛化能力

2. 非线性模型
给线性模型套上一个非线性函数,称之为激活函数

layers.Dense(256, activation='relu') # 长度为256的向量
3. 多层神经网络
-
将前一层神经元的输出值作为下一 层的输入值
-
将最后一层的输出值作为模型的输出值
-
几个比较基础的概念
- 输入层:数据节点所在的层
- 网络层:输出
连同它的网络层参数
- 隐藏层:网络层中间的层
- 输出层:最后一层
体验手写数字识别
网络搭建
# 构建3层网络
model = keras.Sequential([
layers.Dense(256, activation='relu'), # 第1层的输出节点数为256
layers.Dense(128, activation='relu'),
layers.Dense(10) # 输出层节点数设计为10
])
模型训练
对数据集中的所有图片迭代一遍叫做一个Epoch
with tf.GradientTape() as tape: # 构建梯度记录环境
# 1. 拍平 [b, 28, 28] ---> [b, 784]
x = tf.reshape(x, (-1, 28*28))
# 2. 输出 [b,784] --->[b,10]
out = model(x)
# 3. 计算梯度:自带的自动求导函数求解
grads = tape.gradient(loss, model.trainable_variables)
# 4. 更新网络参数
optimizer.apply_gradients = (zip(grads, model.trainable_variables))
网友评论