提交 ae817627 编写于 作者: S Shan Yi

fix_fit_a_line

上级 4efd5b7e
```eval_rst
.. _quick_start_fit_a_line:
```
# 线性回归
让我们从经典的线性回归(Linear Regression \[[1](#参考文献)\])模型开始这份教程。在这一章里,你将使用真实的数据集建立起一个房价预测模型,并且了解到机器学习中的若干重要概念。
本教程源代码目录在[book/fit_a_line](https://github.com/PaddlePaddle/book/tree/develop/01.fit_a_line), 初次使用请参考PaddlePaddle[安装教程](https://github.com/PaddlePaddle/book/blob/develop/README.cn.md#运行这本书)
本教程源代码目录在[book/fit_a_line](https://github.com/PaddlePaddle/book/tree/develop/01.fit_a_line), 初次使用请参考PaddlePaddle[安装教程](https://github.com/PaddlePaddle/book/blob/develop/README.cn.md#运行这本书),更多内容请参考本教程的[视频课堂](http://bit.baidu.com/course/detail/id/137.html)
## 背景介绍
给定一个大小为$n$的数据集 ${\{y_{i}, x_{i1}, ..., x_{id}\}}_{i=1}^{n}$,其中$x_{i1}, \ldots, x_{id}$是第$i$个样本$d$个属性上的取值,$y_i$是该样本待预测的目标。线性回归模型假设目标$y_i$可以被属性间的线性组合描述,即
......@@ -17,9 +14,10 @@ $$y_i = \omega_1x_{i1} + \omega_2x_{i2} + \ldots + \omega_dx_{id} + b, i=1,\ldo
## 效果展示
我们使用从[UCI Housing Data Set](https://archive.ics.uci.edu/ml/datasets/Housing)获得的波士顿房价数据集进行模型的训练和预测。下面的散点图展示了使用模型对部分房屋价格进行的预测。其中,每个点的横坐标表示同一类房屋真实价格的中位数,纵坐标表示线性回归模型根据特征预测的结果,当二者值完全相等的时候就会落在虚线上。所以模型预测得越准确,则点离虚线越近。
![BostonHousePricePredictions](./image/predictions.png)
<p align="center">图1. 预测值 V.S. 真实值</p>
<p align="center">
<img src = "image/predictions.png" width=400><br/>
图1. 预测值 V.S. 真实值
</p>
## 模型概览
......@@ -42,99 +40,36 @@ $$MSE=\frac{1}{n}\sum_{i=1}^{n}{(\hat{Y_i}-Y_i)}^2$$
### 训练过程
定义好模型结构之后,我们要通过以下几个步骤进行模型训练
1. 初始化参数,其中包括权重$\omega_i$和偏置$b$,对其进行初始化(如0均值,1方差)。
2. 网络正向传播计算网络输出和损失函数。
3. 根据损失函数进行反向误差传播 ([backpropagation](https://en.wikipedia.org/wiki/Backpropagation)),将网络误差从输出层依次向前传递, 并更新网络中的参数。
4. 重复2~3步骤,直至网络训练误差达到规定的程度或训练轮次达到设定值。
1. 初始化参数,其中包括权重$\omega_i$和偏置$b$,对其进行初始化(如0均值,1方差)。
2. 网络正向传播计算网络输出和损失函数。
3. 根据损失函数进行反向误差传播 ([backpropagation](https://en.wikipedia.org/wiki/Backpropagation)),将网络误差从输出层依次向前传递, 并更新网络中的参数。
4. 重复2~3步骤,直至网络训练误差达到规定的程度或训练轮次达到设定值。
## 数据集
### 数据集介绍
这份数据集共506行,每行包含了波士顿郊区的一类房屋的相关信息及该类房屋价格的中位数。其各维属性的意义如下:
<p align="center">
<table>
<thead>
<tr>
<th>属性名</th>
<th>解释</th>
<th>类型</th>
</tr>
</thead>
<tbody>
<tr>
<td>CRIM</td>
<td>该镇的人均犯罪率</td>
<td>连续值</td>
</tr>
<tr>
<td>ZN</td>
<td>占地面积超过25,000平方呎的住宅用地比例</td>
<td>连续值</td>
</tr>
<tr>
<td>INDUS</td>
<td>非零售商业用地比例</td>
<td>连续值</td>
</tr>
<tr>
<td>CHAS</td>
<td>是否邻近 Charles River</td>
<td>离散值,1=邻近;0=不邻近</td>
</tr>
<tr>
<td>NOX</td>
<td>一氧化氮浓度</td>
<td>连续值</td>
</tr>
<tr>
<td>RM</td>
<td>每栋房屋的平均客房数</td>
<td>连续值</td>
</tr>
<tr>
<td>AGE</td>
<td>1940年之前建成的自用单位比例</td>
<td>连续值</td>
</tr>
<tr>
<td>DIS</td>
<td>到波士顿5个就业中心的加权距离</td>
<td>连续值</td>
</tr>
<tr>
<td>RAD</td>
<td>到径向公路的可达性指数</td>
<td>连续值</td>
</tr>
<tr>
<td>TAX</td>
<td>全值财产税率</td>
<td>连续值</td>
</tr>
<tr>
<td>PTRATIO</td>
<td>学生与教师的比例</td>
<td>连续值</td>
</tr>
<tr>
<td>B</td>
<td>1000(BK - 0.63)^2,其中BK为黑人占比</td>
<td>连续值</td>
</tr>
<tr>
<td>LSTAT</td>
<td>低收入人群占比</td>
<td>连续值</td>
</tr>
<tr>
<td>MEDV</td>
<td>同类房屋价格的中位数</td>
<td>连续值</td>
</tr>
</tbody>
</table>
</p>
| 属性名 | 解释 | 类型 |
| ------| ------ | ------ |
| CRIM | 该镇的人均犯罪率 | 连续值 |
| ZN | 占地面积超过25,000平方呎的住宅用地比例 | 连续值 |
| INDUS | 非零售商业用地比例 | 连续值 |
| CHAS | 是否邻近 Charles River | 离散值,1=邻近;0=不邻近 |
| NOX | 一氧化氮浓度 | 连续值 |
| RM | 每栋房屋的平均客房数 | 连续值 |
| AGE | 1940年之前建成的自用单位比例 | 连续值 |
| DIS | 到波士顿5个就业中心的加权距离 | 连续值 |
| RAD | 到径向公路的可达性指数 | 连续值 |
| TAX | 全值财产税率 | 连续值 |
| PTRATIO | 学生与教师的比例 | 连续值 |
| B | 1000(BK - 0.63)^2,其中BK为黑人占比 | 连续值 |
| LSTAT | 低收入人群占比 | 连续值 |
| MEDV | 同类房屋价格的中位数 | 连续值 |
### 数据预处理
#### 连续值与离散值
......@@ -148,8 +83,10 @@ $$MSE=\frac{1}{n}\sum_{i=1}^{n}{(\hat{Y_i}-Y_i)}^2$$
- 不同的数值范围会导致不同属性对模型的重要性不同(至少在训练的初始阶段如此),而这个隐含的假设常常是不合理的。这会对优化的过程造成困难,使训练时间大大的加长。
- 很多的机器学习技巧/模型(例如L1,L2正则项,向量空间模型-Vector Space Model)都基于这样的假设:所有的属性取值都差不多是以0为均值且取值范围相近的。
![featureScale](./image/ranges.png)
<p align="center">图2. 各维属性的取值范围</p>
<p align="center">
<img src = "image/ranges.png" width=550><br/>
图2. 各维属性的取值范围
</p>
#### 整理训练集与测试集
我们将数据集分割为两份:一份用于调整模型的参数,即进行模型的训练,模型在这份数据集上的误差被称为**训练误差**;另外一份被用来测试,模型在这份数据集上的误差被称为**测试误差**。我们训练模型的目的是为了通过从训练数据中找到规律来预测未知的新数据,所以测试误差是更能反映模型表现的指标。分割数据的比例要考虑到两个因素:更多的训练数据会降低参数估计的方差,从而得到更可信的模型;而更多的测试数据会降低测试误差的方差,从而得到更可信的测试误差。我们这个例子中设置的分割比例为$8:2$
......@@ -167,6 +104,7 @@ $$MSE=\frac{1}{n}\sum_{i=1}^{n}{(\hat{Y_i}-Y_i)}^2$$
import paddle
import paddle.fluid as fluid
import numpy
from __future__ import print_function
```
我们通过uci_housing模块引入了数据集合[UCI Housing Data Set](https://archive.ics.uci.edu/ml/datasets/Housing)
......@@ -182,14 +120,14 @@ import numpy
BATCH_SIZE = 20
train_reader = paddle.batch(
paddle.reader.shuffle(
paddle.dataset.uci_housing.train(), buf_size=500),
batch_size=BATCH_SIZE)
paddle.reader.shuffle(
paddle.dataset.uci_housing.train(), buf_size=500),
batch_size=BATCH_SIZE)
test_reader = paddle.batch(
paddle.reader.shuffle(
paddle.dataset.uci_housing.test(), buf_size=500),
batch_size=BATCH_SIZE)
paddle.reader.shuffle(
paddle.dataset.uci_housing.test(), buf_size=500),
batch_size=BATCH_SIZE)
```
### 配置训练程序
......@@ -197,16 +135,25 @@ batch_size=BATCH_SIZE)
```python
def train_program():
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
# feature vector of length 13
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
# feature vector of length 13
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
loss = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_loss = fluid.layers.mean(loss)
loss = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_loss = fluid.layers.mean(loss)
return avg_loss
return avg_loss
```
### Optimizer Function 配置
在下面的 `SGD optimizer``learning_rate` 是训练的速度,与网络的训练收敛速度有关系。
```python
def optimizer_program():
return fluid.optimizer.SGD(learning_rate=0.001)
```
### 定义运算场所
......@@ -222,9 +169,9 @@ place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
```python
trainer = fluid.Trainer(
train_func=train_program,
place=place,
optimizer_func=fluid.optimizer.SGD(learning_rate=0.001))
train_func=train_program,
place=place,
optimizer_func=optimizer_program)
```
### 开始提供数据
......@@ -237,7 +184,7 @@ feed_order=['x', 'y']
除此之外,可以定义一个事件相应器来处理类似`打印训练进程`的事件:
```python
# Specify the directory path to save the parameters
# Specify the directory to save the parameters
params_dirname = "fit_a_line.inference.model"
# Plot data
......@@ -248,27 +195,27 @@ plot_cost = Ploter(train_title, test_title)
step = 0
# event_handler to print training and testing info
# event_handler prints training and testing info
def event_handler_plot(event):
global step
if isinstance(event, fluid.EndStepEvent):
if event.step % 10 == 0: # every 10 batches, record a test cost
test_metrics = trainer.test(
reader=test_reader, feed_order=feed_order)
global step
if isinstance(event, fluid.EndStepEvent):
if event.step % 10 == 0: # record the test cost every 10 seconds
test_metrics = trainer.test(
reader=test_reader, feed_order=feed_order)
plot_cost.append(test_title, step, test_metrics[0])
plot_cost.plot()
plot_cost.append(test_title, step, test_metrics[0])
plot_cost.plot()
if test_metrics[0] < 10.0:
# If the accuracy is good enough, we can stop the training.
print('loss is less than 10.0, stop')
trainer.stop()
if test_metrics[0] < 10.0:
# If the accuracy is good enough, we can stop the training.
print('loss is less than 10.0, stop')
trainer.stop()
# We can save the trained parameters for the inferences later
if params_dirname is not None:
trainer.save_params(params_dirname)
# We can save the trained parameters for the inferences later
if params_dirname is not None:
trainer.save_params(params_dirname)
step += 1
step += 1
```
### 开始训练
......@@ -279,13 +226,13 @@ step += 1
# The training could take up to a few minutes.
trainer.train(
reader=train_reader,
num_epochs=100,
event_handler=event_handler_plot,
feed_order=feed_order)
reader=train_reader,
num_epochs=100,
event_handler=event_handler_plot,
feed_order=feed_order)
```
![trainTestCost](./image/train_and_test.png)
![png](./image/train_and_test.png)
## 预测
提供一个`inference_program`和一个`params_dirname`来初始化预测器。`params_dirname`用来存储我们的参数。
......@@ -296,9 +243,9 @@ feed_order=feed_order)
```python
def inference_program():
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
return y_predict
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
return y_predict
```
### 预测
......@@ -306,13 +253,23 @@ return y_predict
```python
inferencer = fluid.Inferencer(
infer_func=inference_program, param_path=params_dirname, place=place)
infer_func=inference_program, param_path=params_dirname, place=place)
batch_size = 10
tensor_x = numpy.random.uniform(0, 10, [batch_size, 13]).astype("float32")
test_reader = paddle.batch(paddle.dataset.uci_housing.test(),batch_size=batch_size)
test_data = test_reader().next()
test_feat = numpy.array([data[0] for data in test_data]).astype("float32")
test_label = numpy.array([data[1] for data in test_data]).astype("float32")
results = inferencer.infer({'x': test_feat})
print("infer results: (House Price)")
for k in range(0, batch_size-1):
print("%d. %f" % (k, results[0][k]))
results = inferencer.infer({'x': tensor_x})
print("infer results: ", results[0])
print("\nground truth:")
for k in range(0, batch_size-1):
print("%d. %f" % (k, test_label[k]))
```
## 总结
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册