在这一讲中,王校长将会手把手地教大家使用Python编写线性的拟合程序。不了解Python语言的童鞋可以通过官方所给的文档 [1],学习一下基本语法。这一讲王校长将会带大家学习两个用来做机器学习的Python库,分别是Scikit-Learn [2]和TensorFlow [3]。教程中完整的代码都放在了王校长的GitHub目录:https://github.com/physicso/AICourse
这里特别强调,大家要使用Python 2.x版本,不是因为王校长2,是因为Python 3.x不好用,很多语法与2.x也不兼容!
使用Scikit-Learn写拟合的程序非常简单,几行代码就可以搞定。我们使用一个小栗子为大家进行一下示范。
在这个栗子中,我们将根据五道口附近已有的学区房价格(实际的售价可能比我们例子中给出的还要高 ~!~),来拟合出一个房屋大小与售价之间的关系曲线,进而预测一个更大房子的可能售价。我们手中的数据是介个样子的:
房屋尺寸(平方米) | 售价(万元) |
30 | 320 |
40 | 360 |
60 | 400 |
80 | 455 |
100 | 490 |
120 | 546 |
140 | 580 |
接下来咱们上点代码,首先引入两个函数,分别用来作图和做拟合:
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
然后定义一个生成图像句柄(大家可以把“句柄”理解为一个空白的画布)的函数:
def runplt():
plt.figure()
plt.title(u'Apartment Price Curve')
plt.xlabel(u'Size')
plt.ylabel(u'Price')
plt.axis([0, 150, 0, 600])
plt.grid(True)
return plt
接下来我们就可以把数据画出来啦:
plt = runplt()
X = [[30],[40],[60],[80],[100],[120],[140]]
y = [[220],[260],[300],[355],[390],[446],[480]]
plt.plot(X, y, 'k.')
plt.show()
这段代码的运行结果是一个散点图:
从图中可以看到,房屋尺寸和售价近似呈现一个线性的关系,下面我们就把这条线找出来:
model = LinearRegression()
model.fit(X, y)
那么现在model里面存放的,就是Scikit-Learn为我们拟合出的线性模型。我们使用这个模型来预测一下,如果土豪想买一个160平方米的房子,大概会花多少钱:
print 'The Price of Size 160m^2 Apartment: %.2fW' % model.predict([[160]])[0]
结果是:
The Price of Size 160m^2 Apartment: 633.52W
好贵~
我们画出这条线:
y_pred = model.predict(X)
plt.plot(X, y, 'k.')
plt.plot(X, y_pred, 'g-')
plt.show()
这个栗子就此熟了!
接下来我们介绍点高深的东东,这个神秘的主角叫TF,当然它不是TF Boys,因为TF Boys不是东东……它是TensorFlow。TF最近火爆了各个领域,大家肯定也在新闻中听到过它的飒爽英姿。今天,王校长将教给你如何驯服这个装*神器。
王校长就不跟大家介绍如何安装TF啦,大家可以查看TF的官方文档,不过要注意的是,要运行TF,必须是在Mac或者Linux环境下。大批使用Windows的可怜孩子可以用虚拟机来玩它。与Scikit-Learn不同的是,TF能够充分利用机器中的CPU和GPU进行运算,并且支持集群化计算。所以如果大家只是建立一些简单的模型,Scikit-Learn就已经足够。如果数据量足够大,建议大家还是采用TF。需要补充的是,使用TF还可以进行任意形式函数的拟合 :)
由于Scikit-Learn把内部的所有事情都帮我们做好了,虽然看着灰常Easy,但是我们并不能领悟到这个过程的细节。因此,在下面的TF代码中,我们将会完整地实现拟合和优化的细节。Ready? Let's Go!
既然称为Flow,那么我们就要把要做的事情写成一个图的形式,比如:
我们的线性模型输入是一个向量X,经过模型计算,输出是一个标量y_pred,通过与真实的值y_real比较,我们可以得到成本函数,通过成本函数,可以对线性模型进行优化。
首先,我们需要引入一些必须的库,包括TF和numpy。为啥需要numpy呢?是因为numpy可以大大加速矩阵的处理过程,因此TF的输入均为numpy的array。
import tensorflow as tf
import numpy
随后我们可以定义模型的参数,包括输入X、输出y、权重W,以及偏移b。
X = tf.placeholder("float")
y = tf.placeholder("float")
W = tf.Variable(numpy.random.randn(), name="weight")
b = tf.Variable(numpy.random.randn(), name="bias")
那么我们的预测值就是:
y_pred = tf.add(tf.mul(X, W), b)
可以看到,这里我们使用了线性的模型。通过修改这段代码,我们可以方便地使用任意的拟合函数,包括各种非线性的拟合。
成本函数为:
cost = tf.reduce_sum(tf.pow(y_pred- y,2))/(2 * n_samples)
其中n_samples是我们的样本数目。我们使用梯度下降的方法来对模型进行优化:
learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
第二讲中所提到的各种优化方法,TF都为大家提供了,只需要修改GradientDescentOptimizer便可以使用。这里的学习速率我们定义成了0.01,优化的目标是最小化成本函数。
程序进行到这里时,只是建立了这么一张图,并没有做实质性的变量初始化。给定我们的训练数据:
train_X = numpy.asarray([30.0, 40.0, 60.0, 80.0, 100.0, 120.0, 140.0])
train_Y = numpy.asarray([320.0, 360.0, 400.0, 455.0, 490.0, 546.0, 580])
需要注意的是,输入的数据类型一定与图中给出placeholder的数据类型一致。下面这个命令告诉TF,一切就绪,干!
training_epochs = 1000
display_step = 50
with tf.Session() as sess:
sess.run(tf..initialize_all_variables())
for epoch in range(training_epochs):
for (x_train, y_train) in zip(train_X, train_Y):
sess.run(optimizer, feed_dict={X: x_train, y: y_train})
if epoch % display_step ==0:
print "Epoch:" + '%04d'% (epoch+1) + "cost=" + "{:.9f}".format(sess.run(cost, feed_dict={X: train_X, y: train_Y})) +"W=" + sess.run(W),"b=", sess.run(b)
print "Optimization Finished!"
training_cost = sess.run(cost, feed_dict={X: train_X, y: train_Y})
print "Training cost = " + training_cost + "W = " + sess.run(W) + "b=" + sess.run(b) + '\n'
这里我想跟大家复习一下上一节中的内容,即每一轮迭代应该使用多少样本对模型进行优化。
容易看到,上面的代码中使用的是Full-Batch方法,因此一次的Iteration就是一个Epoch。程序中,我们定义了最大的Iteration次数为1000,也就是过1000遍全量的数据,每50次输出一次中间结果。程序的最后,输出一次成本函数的值和最后得到的模型参数。
熟悉第一讲的童鞋肯定会说,王校长,你忽略了一个重要的步骤!对,这个程序中,我们没有把训练数据分成三个集合:训练集、验证集、测试集,这是因为我们的数据实在是太少了。聪明的各位应该知道如何修改上面的代码把这个环节加进去吧!
[1] https://docs.python.org/2/tutorial/index.html
[2] http://scikit-learn.org/
[3] https://www.tensorflow.org/