我们通常使用TensorFlow来构建一个神经网络。然而,TensorFlow并不限于此。在幕后,TensorFlow是一个具有自动微分能力的张量库。因此,我们可以很容易地用它来解决梯度下降的数值优化问题。在这篇文章中,我们将展示TensorFlow的自动微分引擎autograd是如何工作的。
在完成本教程后,你将学会:
- 什么是TensorFlow中的autograd
- 如何利用autograd和一个优化器来解决一个优化问题
让我们开始吧。
概述 TensorFlow中的Autograd
在TensorFlow 2.x中,我们可以将变量和常量定义为TensorFlow对象,并用它们构建一个表达式。该表达式本质上是变量的一个函数。因此,我们可以推导出其导数函数,即微分或梯度。这个特征是TensorFlow中的许多基本特征之一。深度学习模型将在训练循环中利用这一点。
用一个例子来解释autograd比较容易。在TensorFlow 2.x中,我们可以创建一个常量矩阵,如下所示。
import tensorflow as tf
x = tf.constant([1, 2, 3])
print(x)
print(x.shape)
print(x.dtype)
上面的打印结果。
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
(3,)
<dtype: 'int32'>
这意味着我们创建了一个整数向量(以Tensor对象的形式)。这个向量在大多数情况下可以像NumPy向量一样工作。例如,我们可以做x+x 或2*x ,结果就像我们所期望的那样。TensorFlow带有许多与NumPy相匹配的数组操作的函数,如tf.transpose 或tf.concat 。
在TensorFlow中创建变量也是一样的,比如说。
import tensorflow as tf
x = tf.Variable([1, 2, 3])
print(x)
print(x.shape)
print(x.dtype)
这将打印。
<tf.Variable 'Variable:0' shape=(3,) dtype=int32, numpy=array([1, 2, 3], dtype=int32)>
(3,)
<dtype: 'int32'>
而我们可以应用于Tensor对象的操作(如x+x 和2*x )也可以应用于变量。变量和常量之间的唯一区别是前者允许数值变化,而后者是不可变的。这个区别在我们运行梯度带时很重要,如下所示。
import tensorflow as tf
x = tf.Variable(3.6)
with tf.GradientTape() as tape:
y = x*x
dy = tape.gradient(y, x)
print(dy)
这就打印出来了。
tf.Tensor(7.2, shape=(), dtype=float32)
它的作用如下。我们定义了一个变量x (值为3.6),然后创建了一个梯度带。当梯度带工作时,我们计算y=x*x 或。梯度带监控着变量的操作过程。之后,我们要求梯度带找到导数$$dfrac{dy}{dx}y=x^2y'=2x3.6/times 2=7.2$。
使用autograd进行多项式回归
TensorFlow中的这个功能有什么用?让我们考虑这样一种情况:我们有一个y=f(x)$形式的多项式,我们得到了几个(x,y)f(x)(x,y)。如果找到了多项式,我们应该看到$$y的值与相匹配。它们越接近,我们的估计就越接近于正确的多项式。
这的确是一个数值优化问题,比如我们要使和之间的差值最小。我们可以使用梯度下降法来解决它。
让我们考虑一个例子。我们可以在NumPy中建立一个多项式$f(x)=x^2 + 2x + 3$$,如下所示。
import numpy as np
polynomial = np.poly1d([1, 2, 3])
print(polynomial)
这就打印出来了。
2
1 x + 2 x + 3
我们可以把多项式作为一个函数,比如。
print(polynomial(1.5))
而这将打印8.25 ,因为。
现在我们可以用NumPy从这个函数中生成一些样本。
N = 20 # number of samples
# Generate random samples roughly between -10 to +10
X = np.random.randn(N,1) * 5
Y = polynomial(X)
在上面,X 和Y 都是形状为(20,1) 的 NumPy 数组,它们的关系是 $$y=f(x)f(x)$。
现在假设我们不知道我们的多项式是什么,但它是二次型的。而我们想恢复系数。由于二次多项式的形式是$Ax^2+Bx+C$$,我们有三个未知数要找。我们可以使用我们实现的梯度下降算法,或者使用现有的梯度下降优化器来找到它们。下面演示了它的工作原理。
import tensorflow as tf
# Assume samples X and Y are prepared elsewhere
XX = np.hstack([X*X, X, np.ones_like(X)])
w = tf.Variable(tf.random.normal((3,1))) # the 3 coefficients
x = tf.constant(XX, dtype=tf.float32) # input sample
y = tf.constant(Y, dtype=tf.float32) # output sample
optimizer = tf.keras.optimizers.Nadam(lr=0.01)
print(w)
for _ in range(1000):
with tf.GradientTape() as tape:
y_pred = x @ w
mse = tf.reduce_sum(tf.square(y - y_pred))
grad = tape.gradient(mse, w)
optimizer.apply_gradients([(grad, w)])
print(w)
For循环之前的print 语句给出了三个随机数,如
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[-2.1450958 ],
[-1.1278448 ],
[ 0.31241694]], dtype=float32)>
但是for循环之后的语句给出了与我们的多项式中非常接近的系数。
<tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=
array([[1.0000628],
[2.0002015],
[2.996219 ]], dtype=float32)>
上述代码的作用如下。首先我们创建一个有3个值的变量向量w ,即系数$A,B,C(N,3)Nx^2x$$和1的值。我们使用np.hstack() 函数从矢量X 建立这样一个数组。同样地,我们从NumPy数组Y ,建立TensorFlow常量y 。
之后,我们使用for循环来运行1000次迭代的梯度下降。在每次迭代中,我们以矩阵形式计算x\\times w$$,找到Ax^2+Bx+C$,并将其分配给变量y_pred 。然后我们比较y 和y_pred ,并找出均方误差。接下来,我们得出梯度,即均方误差相对于系数的变化率w 。而基于这个梯度,我们使用梯度下降法来更新w 。
从本质上讲,上述代码是为了找到使均方误差最小的系数w 。
把所有东西放在一起,下面是完整的代码。
import numpy as np
import tensorflow as tf
N = 20 # number of samples
# Generate random samples roughly between -10 to +10
polynomial = np.poly1d([1, 2, 3])
X = np.random.randn(N,1) * 5
Y = polynomial(X)
# Prepare input as an array of shape (N,3)
XX = np.hstack([X*X, X, np.ones_like(X)])
# Prepare TensorFlow objects
w = tf.Variable(tf.random.normal((3,1))) # the 3 coefficients
x = tf.constant(XX, dtype=tf.float32) # input sample
y = tf.constant(Y, dtype=tf.float32) # output sample
optimizer = tf.keras.optimizers.Nadam(lr=0.01)
print(w)
# Run optimizer
for _ in range(1000):
with tf.GradientTape() as tape:
y_pred = x @ w
mse = tf.reduce_sum(tf.square(y - y_pred))
grad = tape.gradient(mse, w)
optimizer.apply_gradients([(grad, w)])
print(w)
使用autograd来解决数学难题
在上面,我们使用了20个样本,这对于拟合一个二次方程来说是绰绰有余的。我们也可以用梯度下降来解决一些数学难题。比如说,下面这个问题。
[ A ] + [ B ] = 9
+ -
[ C ] - [ D ] = 1
= =
8 2
换句话说,我们想找到的值,以便。