让我们尝试将一些直觉和来源与tf
方法结合起来。
总体直觉:
这里介绍的回归是一个监督学习问题。如Russel&Norvig的人工智能中所定义的那样,任务是:
给定一个由m
个输入输出对(x1, y1), (x2, y2), ... , (xm, ym)
组成的训练集(X, y)
,其中每个输出都是由未知函数y = f(x)
生成的,发现一个函数h
,它近似于真实函数f
为此,h
假设函数以某种方式将每个x
与待学习的参数相结合,以便输出尽可能接近相应的y
,并且这适用于整个数据集。希望得到的函数将接近于f
。
但是如何学习这些参数呢? 为了能够学习,模型必须能够评估。这里就要用到成本(也称为损失、能量、优点等...)函数了:它是一个度量函数,比较h
的输出与相应的y
,并惩罚大的差异。
现在应该清楚了学习过程的确切含义:改变参数以实现成本函数的更低值。
线性回归:
您发布的示例执行参数线性回归,使用以平均平方误差作为成本函数的梯度下降进行优化。这意味着:
参数化:参数集是固定的。在整个学习过程中,它们都被保存在完全相同的内存占位符中。
线性:函数h
的输出仅是输入x
和参数之间的线性(实际上是仿射)组合。因此,如果x
和w
是具有相同维度的实值向量,b
是实数,则有h(x,w, b)= w.transposed()*x+b
。Deep Learning Book第107页提供了更多关于这方面的质量见解和直觉。
代价函数:现在这是有趣的部分。平均平方误差是一个凸函数。这意味着它有一个单一的全局最优解,并且可以直接使用一组正常方程式找到(也在DLB中解释)。在您的示例中,使用随机(和/或小批量)梯度下降法:这是优化非凸代价函数(在更高级的模型如神经网络中的情况)或当数据集具有巨大维度时的首选方法(也在DLB中解释)。
梯度下降: tf
已经为您处理了这个问题,因此只需说GD通过跟随其导数“向下”以小步骤最小化代价函数,直到达到一个鞍点。如果您完全需要知道,TF应用的确切技术称为自动微分,这是数值和符号方法之间的一种折衷方案。对于像您这样的凸函数,这个点将是全局最优解,并且(如果您的学习率不太大)它将始终收敛到该点,因此不管您使用哪些值初始化变量。在更复杂的体系结构(如神经网络)中,随机初始化是必要的。关于小批量的管理还有一些额外的代码,但我不会深入讨论,因为这不是您问题的主要焦点。
TensorFlow的方法:
深度学习框架现在主要是通过构建计算图来嵌套大量函数(您可能想看一下我几周前关于DL框架的演示)。为了构建和运行图形,TensoFlow遵循声明式风格,这意味着必须先完全定义和编译图形,然后再部署和执行。如果您还没有阅读过这篇简短的维基文章,非常推荐您阅读。在这种情况下,设置分为两个部分:
首先,您需要定义计算图形,在其中将数据集和参数放入内存占位符中,构建假设和成本函数,并告诉tf
应用哪种优化技术。
然后,在会话中运行计算,库将能够(重新)加载数据占位符并执行优化。
代码:
示例代码紧密遵循此方法:
定义测试数据 X
和标签 Y
,并为它们在图中准备一个占位符(在 feed_dict
部分中提供)。
为参数定义 'W' 和 'b' 占位符。它们必须是 变量,因为它们将在会话期间更新。
按照之前的说明定义 pred
(我们的假设)和 cost
。
从这里开始,代码的其余部分应该更加清晰。关于优化器,正如我所说,tf
已经知道如何处理它,但您可能需要查看梯度下降以获取更多细节(同样,DLB是一个非常好的参考)
干杯!
安德烈斯
代码示例:梯度下降与正规方程
这些小片段生成简单的多维数据集并测试两种方法。请注意,正规方程方法不需要循环,并带来更好的结果。对于小维数(DIMENSIONS<30k),这可能是首选方法:
from __future__ import absolute_import, division, print_function
import numpy as np
import tensorflow as tf
DIMENSIONS = 5
f = lambda(x): sum(x)
noise = lambda: np.random.normal(0,10)
DS_SIZE = 5000
TRAIN_RATIO = 0.6
_train_size = int(DS_SIZE*TRAIN_RATIO)
_test_size = DS_SIZE - _train_size
ALPHA = 1e-8
LAMBDA = 0.5
TRAINING_STEPS = 1000
ds = [[np.random.rand()*1000 for d in range(DIMENSIONS)] for _ in range(DS_SIZE)]
ds = [(x, [f(x)+noise()]) for x in ds]
np.random.shuffle(ds)
train_data, train_labels = zip(*ds[0:_train_size])
test_data, test_labels = zip(*ds[_train_size:])
graph = tf.Graph()
with graph.as_default():
x_train = tf.placeholder(tf.float32, shape=(_train_size, DIMENSIONS))
y_train = tf.placeholder(tf.float32, shape=(_train_size, 1))
x_test = tf.placeholder(tf.float32, shape=(_test_size, DIMENSIONS))
y_test = tf.placeholder(tf.float32, shape=(_test_size, 1))
theta = tf.Variable([[0.0] for _ in range(DIMENSIONS)])
theta_0 = tf.Variable([[0.0]])
train_prediction = tf.matmul(x_train, theta)+theta_0
test_prediction = tf.matmul(x_test, theta) +theta_0
train_cost = (tf.nn.l2_loss(train_prediction - y_train)+LAMBDA*tf.nn.l2_loss(theta))/float(_train_size)
optimizer = tf.train.GradientDescentOptimizer(ALPHA).minimize(train_cost)
test_cost = (tf.nn.l2_loss(test_prediction - y_test)+LAMBDA*tf.nn.l2_loss(theta))/float(_test_size)
with tf.Session(graph=graph) as s:
tf.initialize_all_variables().run()
print("initialized"); print(theta.eval())
for step in range(TRAINING_STEPS):
_, train_c, test_c = s.run([optimizer, train_cost, test_cost],
feed_dict={x_train: train_data, y_train: train_labels,
x_test: test_data, y_test: test_labels })
if (step%100==0):
print("\nAfter", step, "iterations:")
print(" train cost =", train_c); print(" test cost =", test_c)
PARAMETERS_GRADDESC = tf.concat(0, [theta_0, theta]).eval()
print("Solution for parameters:\n", PARAMETERS_GRADDESC)
DIMENSIONS = 5
DS_SIZE = 5000
TRAIN_RATIO = 0.6
_train_size = int(DS_SIZE*TRAIN_RATIO)
_test_size = DS_SIZE - _train_size
f = lambda(x): sum(x)
noise = lambda: np.random.normal(0,10)
LAMBDA = 1e6
ds = [[np.random.rand()*1000 for d in range(DIMENSIONS)] for _ in range(DS_SIZE)]
ds = [([1]+x, [f(x)+noise()]) for x in ds]
np.random.shuffle(ds)
train_data, train_labels = zip(*ds[0:_train_size])
test_data, test_labels = zip(*ds[_train_size:])
graph = tf.Graph()
with graph.as_default():
x_train = tf.placeholder(tf.float32, shape=(_train_size, DIMENSIONS+1))
y_train = tf.placeholder(tf.float32, shape=(_train_size, 1))
theta = tf.Variable([[0.0] for _ in range(DIMENSIONS+1)])
optimum = tf.matrix_solve_ls(x_train, y_train, LAMBDA, fast=True)
with tf.Session(graph=graph) as s:
tf.initialize_all_variables().run()
print("initialized")
opt = s.run(optimum, feed_dict={x_train:train_data, y_train:train_labels})
PARAMETERS_NORMEQ = opt
print("Solution for parameters:\n",PARAMETERS_NORMEQ)
ds = [[np.random.rand()*1000 for d in range(DIMENSIONS)] for _ in range(DS_SIZE)]
ds = [([1]+x, [f(x)+noise()]) for x in ds]
test_data, test_labels = zip(*ds)
h_gd = lambda(x): PARAMETERS_GRADDESC.T.dot(x)
h_ne = lambda(x): PARAMETERS_NORMEQ.T.dot(x)
mse = lambda pred, lab: ((pred-np.array(lab))**2).sum()/DS_SIZE
predictions_gd = np.array([h_gd(x) for x in test_data])
predictions_ne = np.array([h_ne(x) for x in test_data])
cost_gd = mse(predictions_gd, test_labels)
cost_ne = mse(predictions_ne, test_labels)
print("total cost with gradient descent:", cost_gd)
print("total cost with normal equations:", cost_ne)
b
,theta1是你的(一维)W
。由于其凸性,无论你从哪里开始都没有关系!梯度下降就像把球扔进碗里:它会落到全局最小值。在你的情况下,它略高于56。如果你想要更精确(但速度较慢)的结果,请尝试降低学习率并增加迭代次数。如果你想要精确的解决方案,可以尝试使用正规方程方法:https://www.tensorflow.org/versions/r1.1/api_docs/python/tf/matrix - fr_andresw_opt, b_opt = W.eval(), b.eval()
,然后您的预测函数应该可以工作:predict = lambda(x): w_opt*x+b_opt
。顺便说一句,如果我运行代码,我会得到更低的成本:('Training cost=', 0.1288833, 'W=', 0.1152851, 'b=', 1.6928034)
。 - fr_andres36.5961460665
,第二次是:37.3570079133
。这是什么原因? - Vladimir Djukic