【tf.wiki】02-TensorFlow基础示例:线性回归 (分别使用np和ts进行梯度下降预测房价+反归一化还原数据)

知识补充

举例函数\(Z=f(X,Y)\):

  • 偏导数
    • 将X固定,Z的增量除以Y的增量,我们称之为Z对Y的偏导数
    • 同理,我们保持Y值不变,Z值仅随X值改变,Z的增量除以X的增量,我们称之为Z对X的偏导数
  • 梯度
    • 每个点都有一个箭头来表示Z对X的偏导数,每个点都有一个箭头来表示Z对Y的偏导数
    • 我们将这两个箭头向量相加,就得到一个新向量,称之为Z的梯度
    • Z的梯度向量总是指向Z函数增长最大的地方
    • 可以得出梯度是Z=f(X,Y)某一点的含有方向的导数,这个方向导数乘以该点的单位向量,就得到一个准确数值,这个数值就是该点在这个方向上的变换率。

示例说明

考虑一个实际问题,某城市在 2013 年 - 2017 年的房价如下表所示:

年份 2013 - 2017

房价 12000 14000 15000 16500 17500

现在,我们希望通过对该数据进行线性回归,即使用线性模型 y = ax + b 来拟合上述数据,此处 a 和 b 是待求的参数。

首先,我们定义数据,进行基本的归一化操作。

首先对数据进行归一化

import numpy as np

X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)
from sklearn import preprocessing
x_scaler = preprocessing.MinMaxScaler().fit(X_raw.reshape(-1, 1))
y_scaler = preprocessing.MinMaxScaler().fit(y_raw.reshape(-1, 1))

X = x_scaler.transform(X_raw.reshape(1, -1))
y = y_scaler.transform(y_raw.reshape(1, -1))

print(X)
print(y)

print('*'*20, '反向')
print(x_scaler.inverse_transform(X))
print(y_scaler.inverse_transform(y))
# print(preprocessing.minmax_scale.inverse_transform(y))
print(X)
print(y)
[[0.   0.25 0.5  0.75 1.  ]]
[[0.         0.3636365  0.54545474 0.818182   1.        ]]
******************** 反向
[[2013. 2014. 2015. 2016. 2017.]]
[[11999.999 14000.    15000.001 16500.    17500.   ]]
[[0.   0.25 0.5  0.75 1.  ]]
[[0.         0.3636365  0.54545474 0.818182   1.        ]]

接下来,我们使用梯度下降方法来求线性模型y=a*x+b中两个参数 a 和 b 的值;

回顾机器学习的基础知识,对于多元函数 f(x) 求局部极小值,梯度下降 的过程如下:

  • 初始化自变量为 \(x_0\) , k=0

  • 迭代进行下列步骤直到满足收敛条件:

    • 求函数 f(x) 关于自变量的梯度 \(\nabla f(x_k)\)

    • 更新自变量: \(x_{k+1} = x_{k} - \gamma \nabla f(x_k)\) 。这里 \(\gamma\) 是学习率(也就是梯度下降一次迈出的 “步子” 大小)

    • \(k \leftarrow k+1\) (迭代下一轮)

接下来,我们考虑如何使用程序来实现梯度下降方法,求得线性回归的解 \(min_{a, b} L(a, b) = \sum_{i=1}^n(ax_i + b - y_i)^2\) 。

NumPy 下的线性回归

此处的损失函数为均方误差 \(L(x) = \sum_{i=1}^N (ax_i + b - y_i)^2\)。其关于参数 a 和 b 的偏导数为 \(\frac{\partial L}{\partial a} = 2 \sum_{i=1}^N (ax_i + b - y) x_i\),$\frac{\partial L}{\partial b} = 2 \sum_{i=1}^N (ax_i + b - y) $。本例中 $N = 5 $。

由于均方误差取均值的系数$ \frac{1}{N}$ 在训练过程中一般为常数( N 一般为批次大小),对损失函数乘以常数等价于调整学习率,因此在具体实现时通常不写在损失函数中。

NumPy手动计算损失函数

a,b = 0,0

num_epoch = 10000
learning_rate = 5e-4

for e in range(num_epoch):
    # 手动计算损失函数关于自变量(模型参数)的梯度
    y_pred = a* X[0] + b
    grad_a, grad_b = 2* (y_pred - y[0]).dot(X[0]), 2*(y_pred - y[0]).sum()

    # 更新参数
    a, b = a - learning_rate * grad_a, b - learning_rate * grad_b

print(a, b)

Numpy 反归一化,还原数据

# 房价预测对比
print(X_raw)
print(y_raw)
res = X * a + b

print(res)
print(y_scaler.inverse_transform(res.reshape(-1, 1) ))
print(y_scaler.inverse_transform(res.reshape(-1, 1) ).reshape(1, -1))
[2013. 2014. 2015. 2016. 2017.]
[12000. 14000. 15000. 16500. 17500.]
[[0.05756507 0.30165762 0.5457502  0.7898427  1.0339353 ]]
[[12316.606]
 [13659.116]
 [15001.625]
 [16344.134]
 [17686.645]]
[[12316.606 13659.116 15001.625 16344.134 17686.645]]

TensorFlow 下的线性回归

使用 TensorFlow 计算线性回归, 程序的结构和前述 NumPy 的实现非常类似:
这里,TensorFlow 帮助我们做了两件重要的工作:

  • 使用 tape.gradient(ys, xs) 自动计算梯度;
  • 使用tf.keras.optimizers.SGD 自动进行优化计算
  • 使用 optimizer.apply_gradients(grads_and_vars) 自动更新模型参数。
import tensorflow as tf
# python --version
print(tf.__version__)
2.1.0
tf_X = tf.constant(X)
tf_y = tf.constant(y)

tf_a, tf_b = tf.Variable(initial_value=0.), tf.Variable(initial_value=0.)
variables = [tf_a, tf_b]

num_epoch = 10000
optimizer = tf.keras.optimizers.SGD(learning_rate=5e-4)
for e in range(num_epoch):
    # 使用tf.GradientTape()记录损失函数的梯度信息
    with tf.GradientTape() as tape:
        tf_y_pred = tf_a * tf_X + tf_b
        loss = tf.reduce_sum(tf.square(tf_y_pred - tf_y))
    # TensorFlow自动计算损失函数关于自变量(模型参数)的梯度
    grads = tape.gradient(loss, variables)

    # TensorFlow自动根据梯度更新参数
    optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
print('variables', variables)
variables [<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.97637004>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.057565123>]

TensorFlow 反归一化,还原数据

# 房价预测对比
print(X_raw)
print(y_raw)
tf_res = np.array(X * tf_a + tf_b)

print(tf_res)
print(y_scaler.inverse_transform(tf_res.reshape(-1, 1) ))
print(y_scaler.inverse_transform(tf_res.reshape(-1, 1) ).reshape(1, -1))

[2013. 2014. 2015. 2016. 2017.]
[12000. 14000. 15000. 16500. 17500.]
[[0.05756512 0.30165762 0.54575014 0.7898426  1.0339352 ]]
[[12316.608]
 [13659.116]
 [15001.625]
 [16344.134]
 [17686.643]]
[[12316.608 13659.116 15001.625 16344.134 17686.643]]
上一篇:Unity使用RawImage播放视频带有播放暂停功能滑动条可控制快进后退


下一篇:特征工程之特征归一化