tensorflow - TensowFlow GradientDescentOptimizer 在这个例子中做了什么?

标签 tensorflow

我正在尝试做 Stanfords CS20: TensorFlow for Deep Learning Research类(class)。前 2 个讲座很好地介绍了低级管道和计算框架(坦率地说,官方介绍性教程似乎因为我只能理解为虐待狂的原因而直接跳过)。在 lecture 3 ,它开始执行线性回归,并对我来说似乎是一个相当大的认知飞跃。而不是 session.run在张量计算中,它在 GradientDescentOptimizer 上进行。

sess.run(optimizer, feed_dict={X: x, Y:y}) 

完整代码可在 lecture 3 notes 的第 3 页上找到。 .

编辑:代码和数据也可用 at this github - 代码在 examples/03_linreg_placeholder.py 中可用和数据在 examples/data/birth_life_2010.txt
编辑:代码如下根据要求
import tensorflow as tf

import utils

DATA_FILE = "data/birth_life_2010.f[txt"

# Step 1: read in data from the .txt file
# data is a numpy array of shape (190, 2), each row is a datapoint
data, n_samples = utils.read_birth_life_data(DATA_FILE)

# Step 2: create placeholders for X (birth rate) and Y (life expectancy)
X = tf.placeholder(tf.float32, name='X')
Y = tf.placeholder(tf.float32, name='Y')

# Step 3: create weight and bias, initialized to 0
w = tf.get_variable('weights', initializer=tf.constant(0.0))
b = tf.get_variable('bias', initializer=tf.constant(0.0))

# Step 4: construct model to predict Y (life expectancy from birth rate)
Y_predicted = w * X + b 

# Step 5: use the square error as the loss function
loss = tf.square(Y - Y_predicted, name='loss')

# Step 6: using gradient descent with learning rate of 0.01 to minimize loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)

with tf.Session() as sess:
    # Step 7: initialize the necessary variables, in this case, w and b
    sess.run(tf.global_variables_initializer()) 

    # Step 8: train the model
    for i in range(100): # run 100 epochs
        for x, y in data:
            # Session runs train_op to minimize loss
            sess.run(optimizer, feed_dict={X: x, Y:y}) 

    # Step 9: output the values of w and b
    w_out, b_out = sess.run([w, b]) 

我已经完成了 coursera machine learning course当然,所以我(认为)我理解梯度下降的概念。但是我对这个特定案例中发生的事情感到非常困惑。

我期望必须发生的事情:
  • 计算梯度(通过微积分或数值方法)
  • 计算参数变化(alpha 乘以整个数据集上的预测值与实际值)
  • 调整参数
  • 重复上述 N 次(在这种情况下,100 个 epoch 为 100 次)

  • 我知道在实践中你会应用诸如批处理和子集之类的东西,但在这种情况下,我相信这只是在整个数据集上循环 100 次。

    我之前可以(并且已经)实现了这一点。但我正在努力理解上面的代码是如何实现这一目标的。一方面是在每个数据点上调用优化器(即它在 100 个时期的内部循环中,然后是每个数据点)。我本来期望一个优化调用会接收整个数据集。

    问题 1 - 梯度调整是在整个数据集上运行 100 次,还是在整个数据集上运行 100 次,每批 1 次(所以 100*n 次,对于 n 个示例)?

    问题 2 - 优化器如何“知道”如何调整 w 和 b?它只提供了损失张量 - 它是通过图表读回并只是“好吧,w和b是唯一的变量,所以我会摆脱这些”

    问题 2b - 如果是这样,如果您放入其他变量会发生什么?或者更复杂的功能?它是否只是自动神奇地计算前导图中每个变量的梯度调整**

    问题 2c - 据此,我尝试按照教程第 3 页中的建议调整为二次表达式,但最终得到了更高的损失。这是正常的吗?该教程似乎建议它应该更好。至少我希望它不会更糟 - 这是否会改变超参数?

    编辑:我尝试调整为二次方的完整代码在这里。并不是说这与上面的相同,其中第 28、29、30 和 34 行被修改为使用二次预测器。这些编辑(我的解释)是 lecture 3 中建议的内容。第 4 页的注释
    """ Solution for simple linear regression example using placeholders
    Created by Chip Huyen (chiphuyen@cs.stanford.edu)
    CS20: "TensorFlow for Deep Learning Research"
    cs20.stanford.edu
    Lecture 03
    """
    import os
    os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
    import time
    
    import numpy as np
    import matplotlib.pyplot as plt
    import tensorflow as tf
    
    import utils
    
    DATA_FILE = 'data/birth_life_2010.txt'
    
    # Step 1: read in data from the .txt file
    data, n_samples = utils.read_birth_life_data(DATA_FILE)
    
    # Step 2: create placeholders for X (birth rate) and Y (life expectancy)
    X = tf.placeholder(tf.float32, name='X')
    Y = tf.placeholder(tf.float32, name='Y')
    
    # Step 3: create weight and bias, initialized to 0
    # w = tf.get_variable('weights', initializer=tf.constant(0.0)) old single weight
    w = tf.get_variable('weights_1', initializer=tf.constant(0.0))
    u = tf.get_variable('weights_2', initializer=tf.constant(0.0))
    b = tf.get_variable('bias', initializer=tf.constant(0.0))
    
    # Step 4: build model to predict Y
    #Y_predicted = w * X + b  #linear
    Y_predicted = w * X * X + X * u + b  #quadratic
    #Y_predicted = w  # test of nonsense
    
    
    # Step 5: use the squared error as the loss function
    # you can use either mean squared error or Huber loss
    loss = tf.square(Y - Y_predicted, name='loss')
    #loss = utils.huber_loss(Y, Y_predicted)
    
    # Step 6: using gradient descent with learning rate of 0.001 to minimize loss
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)
    
    
    start = time.time()
    writer = tf.summary.FileWriter('./graphs/linear_reg', tf.get_default_graph())
    with tf.Session() as sess:
        # Step 7: initialize the necessary variables, in this case, w and b
        sess.run(tf.global_variables_initializer()) 
    
        # Step 8: train the model for 100 epochs
        for i in range(100): 
            total_loss = 0
            for x, y in data:
                # Session execute optimizer and fetch values of loss
                _, l = sess.run([optimizer, loss], feed_dict={X: x, Y:y}) 
                total_loss += l
            print('Epoch {0}: {1}'.format(i, total_loss/n_samples))
    
        # close the writer when you're done using it
        writer.close() 
    
        # Step 9: output the values of w and b
        w_out, b_out = sess.run([w, b]) 
    
    print('Took: %f seconds' %(time.time() - start))
    print(f'w = {w_out}')
    
    # plot the results
    plt.plot(data[:,0], data[:,1], 'bo', label='Real data')
    plt.plot(data[:,0], data[:,0] * w_out + b_out, 'r', label='Predicted data')
    plt.legend()
    plt.show()
    

    对于线性预测器,我失去了(这与讲义一致):
    Epoch 99: 30.03552558278714
    

    对于我在二次方的尝试,我失去了:
    Epoch 99: 127.2992221294363
    

    最佳答案

  • 在您链接的代码中,它是 100 个时期,每批次 1 个(假设 data 的每个元素都是单个输入)。 IE。计算关于单个示例的损失梯度,更新参数,转到下一个示例……直到遍历整个数据集。这样做100次。
  • 很多事情发生在那minimize优化器的调用。实际上,您只需要考虑成本:在幕后,Tensorflow 将计算成本计算中涉及的所有请求变量的梯度(我们将在稍后讨论)(它可以从计算图中推断出这一点)并返回一个“应用”渐变的操作。这意味着一个操作接受所有请求的变量并为它们分配一个新值,例如 tf.assign(var, var - learning_rate*gradient) .这与您提出的另一个问题有关:minimize只返回一个操作,这没有任何作用!在 session 中运行此操作将每次执行“渐变步骤”。

  • 至于哪些变量实际受此操作影响:您可以将其作为参数提供给 minimize称呼! See here -- 参数是 var_list .如果没有给出,Tensorflow 将简单地使用所有“可训练变量”。默认情况下,您使用 tf.Variable 创建的任何变量或 tf.get_variable是可训练的。但是你可以通过 trainable=False这些函数创建的变量(默认情况下)不会受到 minimize 返回的操作的影响。 .玩这个!看看如果您将某些变量设置为不可训练,或者您传递自定义 var_list 会发生什么情况至 minimize .
    通常,Tensorflow 的“整体思想”是它可以“神奇地”仅基于模型的前馈描述来计算梯度。
    编辑:这是可能的,因为机器学习模型(包括深度学习)由非常简单的构建块组成,例如矩阵乘法和主要的逐点非线性。这些简单的块也有简单的导数,可以通过链式法则组成。您可能想阅读反向传播算法。
    对于非常大的模型,肯定需要更长的时间。但是,只要在所有组件都定义了导数的计算图中有一条清晰的“路径”,它总是可能的。
    至于这是否会产生较差的模型:是的,这是深度学习的一个基本问题。非常复杂/深度的模型会导致高度非凸的成本函数,这些成本函数很难用梯度下降等方法进行优化。

    关于二次函数:看起来这里有两个问题。
  • 没有足够的训练时期。更复杂的问题(在这种情况下,我们有更多变量)可能只需要更长的时间来训练。例如。使用您的设置,我可以在使用二次函数大约 330 个时期后达到 ~58 的成本。
  • 学习率。以上仍然是可疑的,因为使用更多变量我们肯定能够得到更好的结果(只要这些变量的输入不是多余的),并且由于这是一个简单的线性回归问题梯度下降应该能够找到它们.在这种情况下,学习率通常是问题所在。我将其更改为 0.0001(降低了 10 倍),并且在大约 3400 个 epoch 之后成本降至 30 以下(还没有测试它到底有多低)。现在显然较低的学习率会导致训练速度变慢,但它们通常在最后是必要的,以避免“跳过”更好的解决方案。这就是为什么在实践中,通常会进行某种学习率退火——从一个大的学习率开始,一开始进步很快,然后随着训练的进行逐渐变小。一般而言,学习率(及其退火计划)是机器学习问题中最需要调整的超参数。
    还有Adam等方法使用“自适应”学习率。通常,未调谐的自适应方法会优于未调谐的梯度下降法,因此它们适用于快速实验。然而,经过良好调整的梯度下降通常会反过来胜过它们。
  • 关于tensorflow - TensowFlow GradientDescentOptimizer 在这个例子中做了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49434400/

    相关文章:

    linux - Tensorflow资源耗尽但没有资源耗尽

    python - Tensorflow:使用 py_func 的自定义数据读取器

    python - tf.reduce_sum() uint8 出现意外结果

    Tensorflow:我可以将多个 name_scope 合并为一个以进行优化器更新吗?

    python - 通过 pip 安装后 Tensorboard 错误

    python - tensorflow 中几个梯度的计算

    python - ValueError : Cannot feed value of shape (256, 0) 对于张量 'Placeholder_2:0' ,其形状为 '(?, 500)'

    python - RuntimeError : tf. placeholder() 与急切执行不兼容

    python - 以 tensorflow 变量作为输入的 keras 前向传递

    python - 从 list_files 创建 tensorflow 数据集