TensorFlow学习(一)
问题引入
某学校决定根据学生德智体成绩评定三好学生。就是说要通过德育分、智育分、体育分求一个综合成绩来评定三好学生。
- 假设这个学校计算综合成绩的规则是:德育分占60%,智育分占30%,体育分10%。
- 学生家长知道了孩子的语文、数学、英语的成绩,也知道了孩子的综合成绩,但是不知道求出综合成绩的方法是什么。现在就是想知道每一项成绩的权重值。
分析问题
已知: 学生三科成绩[70,80,90],学生综合成绩75
求: 三科成绩权重值[0.6,0.3,0.1]
用TensorFlow解决
首先导入需要的模块
# 导入所需模块
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
然后定义数据集合
# 定义数据集合
# 设置随机数种子,主要为了保持重复运行数据一致
np.random.seed(1)
# 200行3列的矩阵,200表示200条学生成绩,3表示每项成绩
x_data = np.random.randint(0,101,[200,3])
# 定义实际权重值
w_ture = np.array([[0.6,0.3,0.1]])
# 根据x_data和w求学生综合成绩y_data,求出结果是[200,1]形状的矩阵
y_data = np.matmul(x_data,w_ture.T)
转换x_data数据类型
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_data,tf.float32)
定义深度学习所需参数和变量
# 定义深度学习需要的变量和参数
# 生成神经网络的参数,3个输入特征(学生成绩),故输入层为3个输入节点;输出层是学生综合成绩,在这次学习中是为了方便计算loss值
w = tf.Variable(tf.random.normal([3,1],stddev=0.1),tf.float32) # 赋初值为正态分布随机数
lr = 0.001 # 定义学习率
loss_result = [] # 记录每次loss值,方便后面画loss图像
epochs = 500 # 设置循环次数
定义训练部分
# 训练部分
for epoch in range(epochs):
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train,w) # y = w1*x1 + w2*x2 + w3*x3 结果是[200,1]形状的矩阵
loss = tf.abs(y-y_data) # 定义loss函数为|y-y_data|
loss_mean = tf.reduce_mean(loss)
loss_result.append(loss_mean) # 将各个epoch的loss平均值记录在loss_result中
# 计算loss函数对w的梯度
grad = tape.gradient(loss,w)
# 实现梯度更新
w.assign_sub(lr * grad) # 参数w自更新
# 每个epoch,打印loss和w信息
print("epoch:",epoch)
print("loss_mean:\n",loss_mean)
print("w:\n",w)
print('-'*50)
试运行
到这里就可以试运行一下代码了
运行结果如下:
--------------------------------------------------
epoch: 496
loss_mean:
tf.Tensor(869.7556, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[5.3367324],
[6.4165573],
[1.3079062]], dtype=float32)>
--------------------------------------------------
epoch: 497
loss_mean:
tf.Tensor(591.71313, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[-5.365268 ],
[-2.7274427],
[-8.395094 ]], dtype=float32)>
--------------------------------------------------
epoch: 498
loss_mean:
tf.Tensor(869.7556, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[5.3367324],
[6.4165573],
[1.3079062]], dtype=float32)>
--------------------------------------------------
epoch: 499
loss_mean:
tf.Tensor(591.71313, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[-5.365268 ],
[-2.7274427],
[-8.395094 ]], dtype=float32)>
--------------------------------------------------
我们发现其中的权重值w一直在两个值之间震荡,这说明我们的学习率需要调整。重新调整学习率为0.0001再运行
lr = 0.0001
--------------------------------------------------
epoch: 496
loss_mean:
tf.Tensor(57.050888, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[-0.11206388],
[-0.18151736],
[-0.4973095 ]], dtype=float32)>
--------------------------------------------------
epoch: 497
loss_mean:
tf.Tensor(89.095985, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[0.9581361 ],
[0.7328826 ],
[0.47299045]], dtype=float32)>
--------------------------------------------------
epoch: 498
loss_mean:
tf.Tensor(57.050888, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[-0.11206388],
[-0.18151736],
[-0.4973095 ]], dtype=float32)>
--------------------------------------------------
epoch: 499
loss_mean:
tf.Tensor(89.095985, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[0.9581361 ],
[0.7328826 ],
[0.47299045]], dtype=float32)>
--------------------------------------------------
发现结果还是在震荡,我们需要更小的学习率。
lr = 0.000001
--------------------------------------------------
epoch: 499
loss_mean:
tf.Tensor(0.6623709, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[0.6057445 ],
[0.3035863 ],
[0.10675556]], dtype=float32)>
--------------------------------------------------
这次运行我们发现结果与我们的真是权重值已经很接近了。
结论
学习率较大的话可能会出现数据震荡现象,这时候需要调小学习率;而学习率过小则会需要更多的训练次数,大家可以尝试。
写完剩下的matplotlib绘制loss图像部分的代码
# 绘制loss图像
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(loss_result)
plt.show()
可以看出loss值仍然在震荡,我们可以继续缩小学习率,但是没有这个必要了。我们可以优化模型。
优化模型
我们可以重新设计误差函数,例如mse均方误差
在模型中我们这么写
loss = tf.reduce_mean(tf.square(y-y_data))
重新设置学习率为0.0001运行试试
lr = 0.0001
epoch: 499
loss_mean:
tf.Tensor(1.2128112e-11, shape=(), dtype=float32)
w:
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[0.59999996],
[0.29999995],
[0.10000006]], dtype=float32)>
--------------------------------------------------
数据很精确,误差甚至只有10e-11数量级
可以发现loss值在训练次数很少的时候就已经变得很小了,我们可以尝试减少训练次数看看结果。
epochs = 50
可以看到在循环次数为10次时误差值loss就已经很小了。说明这个误差函数是很高效的。
完整代码
# 已知学生成绩[70,80,90],以及学生综合成绩75
# 求权重值: w = 0.6,0.3,0.1
# 导入所需模块
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 定义数据集合
# 设置随机数种子,主要为了保持重复运行数据一致
np.random.seed(1)
# 200行3列的矩阵,200表示200条学生成绩,3表示每项成绩
x_data = np.random.randint(0,101,[200,3])
# 定义实际权重值
w_ture = np.array([[0.6,0.3,0.1]])
# 根据x_data和w求学生综合成绩y_data,求出结果是[200,1]形状的矩阵
y_data = np.matmul(x_data,w_ture.T)
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_data,tf.float32)
# 定义深度学习需要的变量和参数
# 生成神经网络的参数,3个输入特征(学生成绩),故输入层为3个输入节点;输出层是学生综合成绩,在这次学习中是为了方便计算loss值
w = tf.Variable(tf.random.normal([3,1],stddev=0.1),tf.float32) # 赋初值为正态分布随机数
lr = 0.0001 # 定义学习率
loss_result = [] # 记录每次loss值,方便后面画loss图像
epochs = 500 # 设置循环次数
# 训练部分
for epoch in range(epochs):
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train,w) # y = w1*x1 + w2*x2 + w3*x3 结果是[200,1]形状的矩阵
loss = tf.reduce_mean(tf.square(y-y_data)) # 定义loss函数为均方误差mse
loss_mean = tf.reduce_mean(loss)
loss_result.append(loss_mean) # 将各个epoch的loss平均值记录在loss_result中
# 计算loss函数对w的梯度
grad = tape.gradient(loss,w)
# 实现梯度更新
w.assign_sub(lr * grad) # 参数w自更新
# 每个epoch,打印loss和w信息
print("epoch:",epoch)
print("loss_mean:\n",loss_mean)
print("w:\n",w)
print('-'*50)
# 绘制loss图像
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(loss_result)
plt.show()