@@@@@@@@@@@@@@@@@@@@
基于MOOC中国慕课大学,浙江大学城市学院课程:深度学习应用开发-TensorFlow实践
基于Tensorflow的版本: 2.0.0-beta0 和 Jupyter 编程工具
@@@@@@@@@@@@@@@@@@@@
有监督学习实例:
通过给予的 60000 条 训练集 数据 和 10000 条 测试集 数据,来给不同的手写数字图象进行分类。
加载tensorflow库等
# 这是一个 有监督学习 的分类问题
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
通过接口下载数据
# 通过接口去下载数据
mnist = tf.keras.datasets.mnist
(train_images, train_labels),(test_images,test_labels) = mnist.load_data()
读取数据
# 本例中包含了 60000 条数据作为 训练集,10000 条数据作为 测试集
print("Train image shape:",train_images.shape,"Train label",train_labels.shape)
# 每条数据是以图像形式存放的 ,都是28像素 * 28像素的 28*28=784
print("Test image shape:",test_images.shape,"Test label",test_labels.shape)
显示结果如下图所示:
训练集的 特征数据 是 60000 条,每条数据是 2 维矩阵,28行 乘 28列 ,标签数据 是一个标量
测试集的 特征数据 是 10000 条,每条数据是 2 维矩阵,28行 乘 28列 ,标签数据 是一个标量
显示数据的基本信息
# 显示训练集的特征数据
print("image data:",train_images[0])
# 查看训练集标签数据
print("label data:",train_labels[0])
定义显示图像的函数,用来查看数据
# 定义 显示图像的函数,用来查看数据
def plot_image(image):
# 把图片绘制成 28 * 28的 灰度模式(只有灰和白) 显示
plt.imshow(image.reshape(28,28),cmap="binary")
plt.show()
plt.imshow()第二个参数是这个图像的模式参数,“binary”表示以灰度模式(只有黑色和白色)显示。
plt.imshow()函数中的图像数据参数支持以下数据形状:
# 查看 训练集 数据
plot_image(train_images[0])
如下图所示:图片中显示的数字是 5,由 28 行 28 列组成
划分验证集
# 划分验证集,把训练集后 20% 的数据作为验证集来使用
total_num = len(train_images) # 获取训练集的长度,这里是60000
valid_split = 0.2 # 定义验证集比例
train_num = int (total_num * (1-valid_split)) # 训练集的数目 = 训练集的长度 * (1 - 验证集的比例)
train_x = train_images[:train_num] # 训练集特征
train_y = train_labels[:train_num] # 训练集标签
valid_x = train_images[train_num:] # 验证集特征
valid_y = train_labels[train_num:] # 验证集标签
test_x = test_images # 测试集特征
test_y = test_labels # 测试集标签
数据的 降维 处理和数据 归一化 处理
# 把 28 * 28 的元素拉直成 1行 784列
# 二维变成了一维
train_x = train_x.reshape(-1,784)
valid_x = valid_x.reshape(-1,784)
test_x = test_x.reshape(-1,784)
# 特征数据归一化 除以255.0 ,因为二维数组的每个值在 0~255 之间 颜色
train_x = tf.cast(train_x/255.0,tf.float32)
valid_x = tf.cast(valid_x/255.0,tf.float32)
test_x = tf.cast(test_x/255.0,tf.float32)
train_x[0]
下图所示:数据归一化后的结果 0~1 之间 ,处理后的形状为 shape=(784,)
处理标签数据
这里将数据 变成 独热编码 的形式
# 对标签数据进行独热编码,且分类为10 第一个元素是5,第二个是0
# 0 的话就这样编码[1., 0., 0., ..., 0., 0., 0.],
# 5 的话这样编码[0.,0.,0.,0.,0.,1.,..., 0., 0.],
train_y = tf.one_hot(train_y,depth=10)
valid_y = tf.one_hot(valid_y,depth=10)
test_y = tf.one_hot(test_y,depth=10)
train_y
如上图 所示就是进行此次分类应用的模型,该模型相当于全连接的神经网络
其中 x 代表了输入的数字图片,w代表了权重,b代表了偏置,y代表了 分类 的类别(0-9),
x 是 1 * 784(1行784列) w 是 784 * 10 (784行10列)b 是 1 行 10 列的向量 ,x * w = 1 * 10 (1行10列的矩阵)
x * w + b = y
利用这个softmax函数,我们把 输出的类别值 y 变成了 这个 样本x 在模型中 属于这个类别的 概率,这张图片的 所有 类别 概率和为 1
构建模型
# 构建模型
def model(x,w,b):
pred = tf.matmul(x, w) + b
# softmax 函数 返回的是 x样本 中 被分为 y 类别的概率 (一张图片有10种可能,10个概率值)
return tf.nn.softmax(pred)
定义模型变量
# 以正太分布的随机数初始化权重 W,以常数0初始化偏置 B
# 矩阵 W 784 行 10 列
W = tf.Variable(tf.random.normal([784,10],mean = 0.0,stddev=1.0,dtype=tf.float32))
# B 是一个一维数组,包含十个 0
B = tf.Variable(tf.zeros([10]),dtype = tf.float32)
定义损失函数
损失函数采用:
def loss(x,y,w,b):
pred = model(x,w,b)
# 传入真实的标签值和根据模型预测的样本值
loss_ = tf.keras.losses.categorical_crossentropy(y_true = y,y_pred = pred)
return tf.reduce_mean(loss_) # 返回均值
定义梯度函数
# 定义梯度函数
def grad(x,y,w,b):
with tf.GradientTape() as tape:
loss_ = loss(x, y, w, b)
return tape.gradient(loss_,[w,b]) # 返回梯度向量
# 定义准确率
def accuracy(x,y,w,b):
pred = model(x,w,b) # 获取预测值
# 比较预测值与标签值是否相同 equal 方法比对预测值和标签值,如果两者相等,返回True,否则返回False
correct_prediction = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
# 准确率,将布尔值转换为浮点数,并计算平均值
return tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
training_epochs = 20 # 训练轮数
batch_size = 50 # 单批次训练样本数
learning_rate = 0.001 # 学习率
# 定义梯度下降优化器
optimizer = tf.keras.optimizers.Adam(learning_rate = learning_rate)
total_step = int(train_num/batch_size) # 计算总共训练的轮数
loss_list_train = [] # 保存训练集损失值的列表
loss_list_valid = [] # 保存验证集损失值的列表
acc_list_train = [] # 保存训练集准确率值的列表
acc_list_valid = [] # 保存验证机准确率值的列表
for epoch in range(training_epochs):
for step in range(total_step):
# 每轮、单批次训练样本数的切片
xs = train_x[step * batch_size:(step+1) * batch_size]
ys = train_y[step * batch_size:(step+1) * batch_size]
grads = grad(xs, ys, W, B) # 计算梯度
optimizer.apply_gradients(zip(grads, [W,B])) # 优化器根据梯度自动调整变量w和b
loss_train = loss(train_x, train_y, W, B).numpy() # 当前轮 训练集的损失
loss_valid = loss(valid_x, valid_y, W, B).numpy() # 当前轮 验证集的损失
acc_train = accuracy(train_x, train_y, W, B).numpy()
acc_valid = accuracy(valid_x, valid_y, W, B).numpy()
loss_list_train.append(loss_train)
loss_list_valid.append(loss_valid)
acc_list_train.append(acc_train)
acc_list_valid.append(acc_valid)
print("epoch={:3d},train_loss={:.4f},train_acc={:.4f},val_loss={:.4f},val_acc={:.4f}".format(epoch+1, loss_train, acc_train,loss_valid,acc_valid))
# 损失函数图像
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.plot(loss_list_train,"blue",label = "Train Loss")
plt.plot(loss_list_valid,"red",label = "Vaild Loss")
plt.legend(loc = 1)# 通过参数指定图例位置
# 准确率函数图像
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.plot(acc_list_train,"blue",label = "Train Acc")
plt.plot(acc_list_valid,"red",label = "Vaild Acc")
plt.legend(loc = 1)# 通过参数指定图例位置
# 显示 测试集 的准确率
acc_test = accuracy(test_x,test_y, W, B).numpy()
print("Test Accuracy:",acc_test)
# 定义预测函数
def predict(x,w,b):
pred = model(x,w,b) #计算预测模型
result = tf.argmax(pred,1).numpy()
return result
pred_test = predict(test_x,W,B)
pred_test[0]
# 可视化结果
def plot_images_labels_prediction(images,
labels,
preds,
index = 0,
num = 10 ):
fig = plt.gcf()# 获取当前图表,Get Current Figure
fig.set_size_inches(10,4)
if num > 10:
num = 10
for i in range(0,num):
ax = plt.subplot(2,5,i+1)
ax.imshow(np.reshape(images[index],(28,28)),cmap="binary") # 显示第 index个图像
title = "label = " + str(labels[index]) # 构建 该图上要显示的title信息
if len(preds)>0:
title += ",predict=" + str(preds[index])
ax.set_title(title,fontsize = 10)
ax.set_xticks([]);
ax.set_yticks([]);
index = index + 1
plt.show()
调参过程:
下图展示了训练轮数 20轮,学习率为0.01 时的函数图像
根据图中展示的 红色和蓝色的曲线中可以得到 当前模型对于验证数据集的 误差 越来越大
要寻找的模式是那个 验证误差不大,且损失一直下降,对测试集的准确率更高的
这里还没有过拟合,过拟合的话函数图像会有上升趋势!这样追求的是泛化能力最好的!
下图展示了训练轮数 20轮,学习率为0.005 时的函数图像
下图展示了训练轮数 20轮,学习率为0.001 时的函数图像
下图展示了训练轮数 20轮,学习率为0.00095 时的函数图像
选择第三次 或者 第四次的模型都可以