(1)TensorFlow入门之求二元一次方程

TensorFlow 最基础的应用可以用来拟合方程,即给出 N 个点(x,y),这些点符合一定规律,我们希望推导出其他符合这个规律的 x 对应的 y 值。

最简单的情况是线性的,我们希望能够使用一条直线拟合这几个点,得到方程式完整的内容,即假设 y = a *x b,我们只需要求得 a 和 b 的值就好了,在初中数学中,只需要提供 2 组(x,y),即可通过消元法求得 a 和 b,这是一个很简单的数学问题。但是如果想用 TensorFlow 的比较通用的方式解决这个问题,就不能教机器这样解了,我们必须让机器通过不断尝试的方式,来获得 a 和 b 的值。

我们来实际操作一下,假设我们现在有一个方程 y = 5 * x 13,我们需要让机器通过一些(x,y) 来推导出 a = 5,b = 13。 首先要使用 TensorFlow,需要 import tensorflow 和数学库 numpy,TensorFlow 的数学计算是以 numpy 为基础的(这点我还不是特别确认,可能也可以有其他的数学库,不过他们之间关系紧密):

import tensorflow as tf
import numpy as np

们要提供一系列已经存在的(x,y) 组合,这个叫做训练集,我们先用代码生成 5 组训练集,先随机生成 5 组 x 的值,命名为 t_x(t 为训练 train 的意思),其中使用 np.random.random([5]) 来生成 0 到 1 之间的随机数,将其乘以 10 可以获得 0 到 10 之间的随机数,最后使用 np.floor 函数对其进行取整,并且令数据类型为浮点数 np.float32 以便于计算:

t_x = np.floor(10 * np.random.random([5]),dtype=np.float32)
print t_x

结果如下,其中随机数每次执行会不一样:

[ 4.  2.  3.  2.  9.]

然后根据公式求得 t_y 的值:

t_y = t_x * 3.0   8.0
print t_y

结果为:

[ 20.  14.  17.  14.  35.]

重新简单讲解一下,TensorFlow 所有的执行流程会在一个 Session 中执行,可以把它暂时看做执行计算的一个载体。我们要在执行前,构造计算的规则,对于计算量的表示,目前只需要知道 2 种,一种是输入量,在 TensorFlow 中以占位符 placeholder 表示,另一种是变量,以 Variable 表示。我们的训练集是在计算过程中以输入表示,因此将其定义为占位符,它的类型为浮点类型 tf.float32:

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

而需要用于输出的 a 和 b 的值,我们将其定义为变量,初始化为浮点数 0.0,这个初始值并不是特别重要,因为 TensorFlow 在训练的过程中,会不断调整这两个值,这个后面会详细说明:

a = tf.Variable(0.0)
b = tf.Variable(0.0)

而在 TensorFlow 的 Session 内部,我们需要根据内部 x,a,b 的值,求得当前的 y 的值 curr_y,因此按照线性公式使用 x,a,b 定义 curr_y,这行语句执行时并不会进行真正的计算,只是仅仅描述他们的关系:

curr_y = x * a   b

得到了当前的 y 值 curr_y,我们就要和我们提供的训练集中对应的 y 值进行比较,使得差异最小,这个差异在机器学习中称为损失函数(Loss function),当损失函数值最低时,就可以认为找到了一个比较好的值,当然实际应用中会有一些局部最小值,这个本例不涉及到,就不讨论了。一般来说,可以使用他们的方差来描述损失函数,因为 TensorFlow 能够很好的支持矩阵运算,而 curr_y 和 y 都可以看做是 1 行 5 列的一个矩阵,因此损失函数可以定义为矩阵各元素之差的平方之和:

loss = tf.reduce_sum(tf.square(curr_y - y
重温一下我们训练的目的,是通过不断调整变量 a 和 b 的值,来达到损失函数值最小的目的。而调整 a 和 b 的值的方法,我们采用一个叫做梯度下降(Gradient descent)的方法,简单来说,可以看做做 loss = fun(a,b) 形成了一个三维曲面。

梯度下降可以看做是一个小球,沿着曲面滚动,它距离地面的面积,就是 loss 函数的值,当它滚动到最低点时,也就找到了损失函数最小的位置(关于局部最小值和梯度下降更深入的内容可以参考原文)。 TensorFlow 中能够很方便地定义梯度下降的训练方法以及描述求损失函数最小值的目的:

optimizer = tf.train.GradientDescentOptimizer(0.001)
train = optimizer.minimize(loss)   
其中梯度下降的参数 0.001 是我调出来的,我目前并不清楚这个值如何更好的调整,太大可能找不到局部最小点,太小会导致训练过慢,也许这就是机器学习工程师有时候被戏称为"调参工程师"的原因? 至此,我们的 TensorFlow 描述部分已经完成了,可以开始进入执行流程了,首先,我们要创建一个 Session 用于执行对于变量,我们需要进行初始化操作,内部会对变量进行内存的分配操作,这个内存会在 Session 关闭时被释放:
sess = tf.Session()
sess.run(tf.global_variables_initializer())
然后我们可以对数据开始训练,第一个参数是训练的内容 train,第二个参数是指定变量 x 和 y 对应的实际值:
sess.run(train, {x:t_x, y:t_y})

一般,训练次数和准确度是有关系的,我通过"调参",确定训练 10000 次,在每次训练后,把当前的 a,b 和损失函数 loss 的值打印出来,需要注意的是,TensorFlow 中的值需要在 sess.run 中执行才能看到结果,如果需要得到多个值,可以将其放到一个数组 []中,因此打印 a,b 和 loss 的值需要放到 sess.run 中执行,同时也要将 t_x 和 t_y 传入:

for i in range(10000):
        sess.run(train, {x:t_x, y:t_y})
        print sess.run([a,b,loss],{x:t_x, y:t_y})

完整的 Python 代码如下:

#!/usr/bin/python
#coding=utf-8
import tensorflow as tf
import numpy as np

tf.logging.set_verbosity(tf.logging.ERROR)              #日志级别设置成 ERROR,避免干扰
np.set_printoptions(threshold='nan')                    #打印内容不限制长度

t_x = np.floor(10 * np.random.random([5]),dtype=np.float32)
print t_x

t_y = t_x * 3.0   8.0
print t_y

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
a = tf.Variable(0.0)
b = tf.Variable(0.0)
curr_y = x * a   b

loss = tf.reduce_sum(tf.square(curr_y - y))             #损失函数,实际输出数据和训练输出数据的方差
optimizer = tf.train.GradientDescentOptimizer(0.001)
train = optimizer.minimize(loss)                        #训练的结果是使得损失函数最小

sess = tf.Session()                                     #创建 Session
sess.run(tf.global_variables_initializer())             #变量初始化

for i in range(10000):
        sess.run(train, {x:t_x, y:t_y})
        print sess.run([a,b,loss],{x:t_x, y:t_y})

exit(0)

执行结果如下:
$ python ./test1.py 
[ 4. 2. 3. 2. 9.]
[ 20. 14. 17. 14. 35.]
[1.0040001, 0.2, 1381.1299]
[1.7710881, 0.35784, 839.84033]
[2.3569665, 0.48341811, 522.96967]
[2.8042414, 0.58430529, 337.39871]
[3.1455021, 0.66629255, 228.64702]
[3.4056759, 0.73380953, 164.84021]
[3.6038294, 0.7902444, 127.32993]
[3.7545466, 0.83818877, 105.2057]
[3.8689826, 0.87962502, 92.084335]
[3.9556696, 0.91606945, 84.231171]
[4.0211344, 0.94868195, 79.461243]
[4.0703683, 0.97834975, 76.496269]
[4.1071901, 1.0057515, 74.588219]
[4.1345205, 1.0314064, 73.299591]
...
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
[3.0000157, 7.9999132, 1.0950316e-08]
在刚开始执行的时候,代码打印出训练集 t_x 和 t_y 的值,然后开始进行训练,a 和 b 的值快速增长,损失函数也在不断减少,最后 a 的值停留在 3.0000157,b 的值停留在 7.9999132,损失函数则为 1.0950316e-08,可见与结果 a=3,b=8 已经非常接近了,如果要更加接近结果,可以尝试降低梯度下降学习速率参数。这样就达到了求 a 和 b 的值的目的。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用 TensorFlow 解决偏微分方程的基本代码: ```python import tensorflow as tf # 定义偏微分方程 def pde(x, t): return tf.sin(tf.math.pi*x)*tf.exp(-t) # 初始化参数 x = tf.linspace(0., 1., 100) t = tf.linspace(0., 1., 100) X, T = tf.meshgrid(x, t) X = tf.reshape(X, [-1, 1]) T = tf.reshape(T, [-1, 1]) X_T = tf.concat([X, T], axis=1) # 定义神经网络 input_layer = tf.keras.layers.Input(shape=(2,)) hidden_layer_1 = tf.keras.layers.Dense(32, activation='relu')(input_layer) hidden_layer_2 = tf.keras.layers.Dense(32, activation='relu')(hidden_layer_1) output_layer = tf.keras.layers.Dense(1)(hidden_layer_2) model = tf.keras.models.Model(inputs=input_layer, outputs=output_layer) # 定义损失函数 def loss_fn(model, x, t): with tf.GradientTape() as tape: tape.watch([x, t]) X_T = tf.concat([x, t], axis=1) u = model(X_T) u_x = tape.gradient(u, x) u_t = tape.gradient(u, t) pde_res = pde(x, t) - u_t + u_x loss = tf.reduce_mean(tf.square(pde_res)) return loss # 定义优化器 optimizer = tf.keras.optimizers.Adam(learning_rate=0.01) # 训练模型 for epoch in range(1000): with tf.GradientTape() as tape: loss = loss_fn(model, X, T) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) if epoch % 100 == 0: print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, 1000, loss.numpy())) ``` 其中,`pde(x, t)` 函数表示偏微分方程,`model` 表示神经网络模型,`loss_fn(model, x, t)` 函数表示损失函数,`optimizer` 表示优化器。在训练模型时,需要循环调用 `optimizer.apply_gradients()` 函数来更新模型的参数,并计算损失函数的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值