在此示例中,TensowFlow GradientDescentOptimizer做什么?

fos*_*ndy 5 tensorflow

我正在尝试做斯坦福大学CS20:TensorFlow深度学习研究课程。前两节讲座很好地介绍了低级管道和计算框架(坦率地说,官方入门教程似乎由于我只能理解为虐待狂而跳过了)。在第3课中,它开始执行线性回归,并在我看来是相当沉重的认知飞跃。它不是session.run在张量计算上而是在GradientDescentOptimizer上执行。

sess.run(optimizer, feed_dict={X: x, Y:y}) 
Run Code Online (Sandbox Code Playgroud)

完整的代码可在第3 讲笔记的第3页上找到。

编辑:此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]) 
Run Code Online (Sandbox Code Playgroud)

我已经完成了Coursera机器学习课程,所以(我认为)我了解Gradient Descent的概念。但是我对这种特定情况下发生的事情一无所知。

我期望发生的事情:

  • 计算梯度(通过微积分或数值方法)
  • 计算参数变化(alpha乘以整个数据集的预测值与实际值)
  • 调整参数
  • 重复以上N次(在这种情况下,将100个历元重复100次)

我知道在实践中您会应用批处理和子集之类的方法,但是在这种情况下,我认为这只是遍历整个数据集100次。

我可以(并且已经)实现了这一点。但是我正在努力弄清楚上面的代码如何实现这一目标。一方面是在每个数据点上调用了优化器(即,它在100个纪元的内循环中,然后在每个数据点中)。我本来希望接受整个数据集的优化调用。

问题1-梯度调整是对整个数据集进行100次操作,还是对整个数据集进行1次的100次操作(对于n个示例,则为100 * n次)?

问题2-优化器如何“知道”如何调整w和b?它只是提供了损失张量-它是通过​​图形读回来的,并且只是“嗯,w和b是唯一的变量,所以我会从那些中摇摆一下”

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

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

编辑:我尝试调整为二次方的完整代码在这里。这与上面的第28、29、30和34行修改为使用二次预测器的方法不同。这些编辑(根据我的解释)是第4页第3讲笔记中建议的内容

""" 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()
Run Code Online (Sandbox Code Playgroud)

对于线性预测变量,我会有所损失(这与讲义一致):

Epoch 99: 30.03552558278714
Run Code Online (Sandbox Code Playgroud)

对于二次方,我迷失了:

Epoch 99: 127.2992221294363
Run Code Online (Sandbox Code Playgroud)

xdu*_*ch0 5

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

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

关于二次函数:看起来这里有两个问题。

  1. 没有足够的培训纪元。更复杂的问题(在这种情况下,我们有更多的变量)可能只需要更长的培训时间。例如,使用您的设置,在使用二次函数约330个纪元后,我的费用大约为58。
  2. 学习率。上面的内容仍然令人怀疑,因为有了更多的变量,我们肯定应该能够获得更好的结果(只要这些变量的输入不是多余的),并且由于这是一个简单的线性回归问题,梯度下降应该能够找到它们。在这种情况下,学习率通常是问题。我将其更改为0.0001(降低了10倍),并在大约3400个纪元后达到了低于30的成本(还没有测试其降低的幅度)。现在很明显,较低的学习率会导致培训速度变慢,但通常需要在最后阶段避免“跳过”更好的解决方案。这就是为什么在实践中通常会进行某种学习率退火的原因-从较大的学习率开始,以便在一开始就快速进步,然后随着训练的进行逐渐缩小。通常,学习速率(及其退火时间表)是需要在机器学习问题中进行最多调整的超参数。
    也有诸如Adam之类的方法使用“自适应”学习率。通常,未调整的自适应方法将胜过未调整的梯度下降,因此它们适合快速实验。但是,调整良好的梯度下降通常会反过来胜过它们。