【TensorFlow】通过两个简单的例子实现反向传播

回归算法示例

# python 3.6
# TensorFlow实现反向传播
import tensorflow as tf
import numpy as np

sess = tf.Session()

# 一、回归算法
# 从均值为1、标准差为0.1的正态分布中抽样随机数,
# 然后乘以变量A,损失函数为L2正则损失函数。
# 理论上,A的最优值是10,因为生成的样例数据均值是1。

# 1.生成数据 创建占位符和变量A
x_vals = np.random.normal(1,0.1,100)
y_vals = np.repeat(10.,100)
x_data = tf.placeholder(shape=[1],dtype=tf.float32)
y_target = tf.placeholder(shape=[1],dtype=tf.float32)
A = tf.Variable(tf.random_normal(shape=[1]))

# 2.增加乘法操作
my_output = tf.multiply(x_data,A)

# 3.增加L2正则损失函数
loss = tf.square(my_output-y_target)

# 4.初始化所有变量
init = tf.global_variables_initializer()
sess.run(init)

# 5.声明变量优化器
# 迭代步长由学习率控制
# 学习率越小 收敛时间越长 学习率过大 可能无法收敛 导致梯度消失或爆炸
my_opt = tf.train.GradientDescentOptimizer(learning_rate=0.02)
train_step = my_opt.minimize(loss)

# 6.训练算法 迭代100次 每25次返回结果 选择一个随机的x和y传入计算图
# tf自动计算损失 调整A偏差来最小化损失
for i in range(100):
    rand_index = np.random.choice(100)
    rand_x = [x_vals[rand_index]]
    rand_y = [y_vals[rand_index]]
    sess.run(train_step,feed_dict={x_data:rand_x,y_target:rand_y})
    if (i+1)%25 == 0:
        print("Step # " + str(i+1) + ' A = ' + str(sess.run(A)))
        print("Loss=" + str(sess.run(loss,feed_dict={x_data:rand_x,y_target:rand_y})))

分类算法示例

# python 3.6
import tensorflow as tf
import numpy as np

# 二、二值分类算法
# 从两个正态分布N(-1,1)和N(3,1)生成100个数。
# 所有从正态分布N(-1,1)生成的数据标为目标类0;
# 从正态分布N(3,1)生成的数据标为目标类1,
# 模型算法通过sigmoid函数将这些生成的数据转换成目标类数据。
# 换句话讲,模型算法是sigmoid(x+A)
# 其中,A是要拟合的变量,理论上A=-1。
# 假设,两个正态分布的均值分别是m1和m2,则达到A的取值时,
# 它们通过-(m1+m2)/2转换成到0等距的值。
# 后面将会在TensorFlow中见证怎样取到相应的值。

# 1.创建计算图
sess = tf.Session()

# 2.生成数据和目标标签、占位符和变量A
x_vals = np.concatenate((np.random.normal(-1,1,50),np.random.normal(3,1,50)))
y_vals = np.concatenate((np.repeat(0.,50),np.repeat(1.,50)))
x_data = tf.placeholder(shape=[1],dtype=tf.float32)
y_target = tf.placeholder(shape=[1],dtype=tf.float32)
# 初始化变量A为10附近的值,远离理论值-1。
# 这样可以清楚地显示算法是如何从10收敛为-1的。
A = tf.Variable(tf.random_normal(mean=10,shape=[1]))

# 3.增加转换操作
my_output = tf.add(x_data,A)

# 4.由于指定的损失函数期望批量数据增加一个批量数的维度,
# 这里使用expand_dims()函数增加维度。
# 之后将讨论如何使用批量变量训练,这次还是一次使用一个随机数据:
my_output_expanded = tf.expand_dims(my_output,0)
y_target_expanded = tf.expand_dims(y_target,0)

# 5.初始化变量A
init = tf.global_variables_initializer()
sess.run(init)

# 6.声明损失函数:带非归一化logits的交叉熵损失函数 用sigmoid转换
xentropy = tf.nn.sigmoid_cross_entropy_with_logits(logits=my_output_expanded,labels=y_target_expanded)

# 7.增加一个优化器函数让TensorFlow知道如何更新和偏差变量
my_opt = tf.train.GradientDescentOptimizer(0.05)
train_step = my_opt.minimize(xentropy)

# 8.通过随机选择的数据迭代几百次 更新变量A 每200次输出loss和A的值
for i in range(1400):
    rand_index=np.random.choice(100)
    rand_x = [x_vals[rand_index]]
    rand_y = [y_vals[rand_index]]
    sess.run(train_step, feed_dict={x_data:rand_x,y_target:rand_y})
    if (i+1)%200 == 0:
        print('Step # ' + str(i+1) + ' A = ' + str(sess.run(A)))
        print('Loss = '+ str(sess.run(xentropy,feed_dict={x_data:rand_x,y_target:rand_y})))

总结

实现反向传播的步骤

  1. 生成数据;
  2. 初始化占位符和变量;
  3. 创建损失函数;
  4. 定义一个优化器算法;
  5. 通过随机数据样本进行迭代,更新变量。

学习率和优化器算法

学习率 优点 缺点 使用场景
结果精确 收敛慢 算法不稳定,降低学习率
收敛快 结果不精确 算法收敛慢,提高学习率

问题
有时,标准梯度下降算法会明显卡顿或者收敛变慢,特别是在梯度为0的附近的点。

解决思路
①TensorFlow的MomentumOptimizer()函数增加了一项势能, 前一次迭代过程的梯度下降值的倒数。

②可以改变的是优化器的步长,理想情况下,对于变化小的变量使用大步长;而变化迅速的变量使用小步长。实现这种优点的常用Adagrad算法。此算法考虑整个历史迭代的变量梯度,TensorFlow中相应功能的实现是AdagradOptimizer()函数。

问题
有时,由于Adagrad算法计算整个历史迭代的梯度,导致梯度迅速变为0。

解决思路
可以用Adadelta算法解决,它限制使用的迭代次数。TensorFlow中相应功能的实现是AdadeltaOptimizer()函数。

发布了23 篇原创文章 · 获赞 64 · 访问量 4380

猜你喜欢

转载自blog.csdn.net/xd963625627/article/details/104790926
今日推荐