Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
d2l-zh
提交
bd0950a1
D
d2l-zh
项目概览
OpenDocCN
/
d2l-zh
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
d2l-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bd0950a1
编写于
11月 08, 2017
作者:
Y
yuwei wang
提交者:
Mu Li
11月 08, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Sync charpter1/linger-regression-scratch (#96)
上级
70d823d0
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
64 addition
and
15 deletion
+64
-15
chapter_supervised-learning/linear-regression-scratch.md
chapter_supervised-learning/linear-regression-scratch.md
+64
-15
img/onelayer.png
img/onelayer.png
+0
-0
未找到文件。
chapter_supervised-learning/linear-regression-scratch.md
浏览文件 @
bd0950a1
# 线性回归 --- 从0开始
# 线性回归 --- 从0开始
虽然强大的深度学习框架可以减少很多重复性工作,但如果你过于依赖它提供的便利抽象,那么你可能不会很容易地理解到底深度学习是如何工作的。所以
我们的第一个教程是如何只利用ndarray和autograd来实现一个线性回归的训练。
尽管强大的深度学习框架可以减少大量重复性工作,但若过于依赖它提供的便利,你就会很难深入理解深度学习是如何工作的。因此,
我们的第一个教程是如何只利用ndarray和autograd来实现一个线性回归的训练。
## 线性回归
## 线性回归
给定一个数据点集合
`X`
和对应的目标值
`y`
,线性模型的目标
是找一根线,其由向量
`w`
和位移
`b`
组成,来最好地近似每个样本
`X[i]`
和
`y[i]`
。用数学符号来表示就是我们将学
`w`
和
`b`
来预测,
给定一个数据点集合
`X`
和对应的目标值
`y`
,线性模型的目标
就是找到一条使用向量
`w`
和位移
`b`
描述的线,来尽可能地近似每个样本
`X[i]`
和
`y[i]`
。用数学符号来表示就是:
$$
\b
oldsymbol{
\h
at{y}} = X
\b
oldsymbol{w} + b$$
$$
\b
oldsymbol{
\h
at{y}} = X
\b
oldsymbol{w} + b$$
...
@@ -12,16 +12,20 @@ $$\boldsymbol{\hat{y}} = X \boldsymbol{w} + b$$
...
@@ -12,16 +12,20 @@ $$\boldsymbol{\hat{y}} = X \boldsymbol{w} + b$$
$$
\s
um_{i=1}^n (
\h
at{y}_i-y_i)^2.$$
$$
\s
um_{i=1}^n (
\h
at{y}_i-y_i)^2.$$
你可能会对我们把古老的线性回归作为深度学习的一个样例表示
很奇怪。实际上线性模型是最简单但也可能是最有用的神经网络。一个神经网络就是一个由节点(神经元)和有向边组成的集合。我们一般把一些节点组成层,每一层使用下一层的节点作为输入,并输出给上面层使用。为了计算一个节点值,我们将输入节点值做加权和,然后再加上一个激活函数
。对于线性回归而言,它是一个两层神经网络,其中第一层是(下图橙色点)输入,每个节点对应输入数据点的一个维度,第二层是单输出节点(下图绿色点),它使用身份函数($f(x)=x$)作为激活函数。
你可能会对我们把古老的线性回归作为深度学习的一个样例表示
奇怪。实际上线性模型是最简单、但也是最有用的神经网络。一个神经网络就是一个由节点(神经元)和有向边组成的集合。我们一般把一些节点组成层,每一层先从下面一层的节点获取输入,然后输出给上面的层使用。要计算一个节点值,我们需要将输入节点值做加权和(权数值即
`w`
),然后再加上一个
**激活函数(activation function)**
。对于线性回归而言,它是一个两层神经网络,其中第一层是(下图橙色点)输入,每个节点对应输入数据点的一个维度,第二层是单输出节点(下图绿色点),它使用身份函数($f(x)=x$)作为激活函数。
![](
../img/
simple-net-linea
r.png
)
![](
../img/
onelaye
r.png
)
## 创建数据集
## 创建数据集
这里我们使用一个
人工数据集来把事情弄简单些,因为这样我们将知道真实的模型是什么样的。具体来说我们使用如下方法来生成数据
这里我们使用一个
数据集来尽量简单地解释清楚,真实的模型是什么样的。具体来说,我们使用如下方法来生成数据;随机数值
`X[i]`
,其相应的标注为
`y[i]`
:
`y[i] = 2 * X[i][0] - 3.4 * X[i][1] + 4.2 + noise`
`y[i] = 2 * X[i][0] - 3.4 * X[i][1] + 4.2 + noise`
使用数学符号表示:
$$y = X
\c
dot w + b +
\e
ta,
\q
uad
\t
ext{for }
\e
ta
\s
im
\m
athcal{N}(0,
\s
igma^2)$$
这里噪音服从均值0和标准差为0.01的正态分布。
这里噪音服从均值0和标准差为0.01的正态分布。
```
{.python .input n=2}
```
{.python .input n=2}
...
@@ -45,6 +49,14 @@ y += .01 * nd.random_normal(shape=y.shape)
...
@@ -45,6 +49,14 @@ y += .01 * nd.random_normal(shape=y.shape)
print(X[0], y[0])
print(X[0], y[0])
```
```
如果有兴趣,可以使用安装包中已包括的 Python 绘图包
`matplotlib`
,生成第二个特征值 (
`X[:, 1]`
) 和目标值
`Y`
的散点图,更直观地观察两者间的关系。
```
{.python .input}
import matplotlib.pyplot as plt
plt.scatter(X[:, 1].asnumpy(),y.asnumpy())
plt.show()
```
## 数据读取
## 数据读取
当我们开始训练神经网络的时候,我们需要不断读取数据块。这里我们定义一个函数它每次返回
`batch_size`
个随机的样本和对应的目标。我们通过python的
`yield`
来构造一个迭代器。
当我们开始训练神经网络的时候,我们需要不断读取数据块。这里我们定义一个函数它每次返回
`batch_size`
个随机的样本和对应的目标。我们通过python的
`yield`
来构造一个迭代器。
...
@@ -79,7 +91,7 @@ b = nd.zeros((1,))
...
@@ -79,7 +91,7 @@ b = nd.zeros((1,))
params = [w, b]
params = [w, b]
```
```
之后训练时我们需要对这些参数求导来更新它们的值,
所以
我们需要创建它们的梯度。
之后训练时我们需要对这些参数求导来更新它们的值,
使损失尽量减小;因此
我们需要创建它们的梯度。
```
{.python .input n=7}
```
{.python .input n=7}
for param in params:
for param in params:
...
@@ -88,7 +100,7 @@ for param in params:
...
@@ -88,7 +100,7 @@ for param in params:
## 定义模型
## 定义模型
线性模型就是将输入和模型
做乘法再加上偏移
:
线性模型就是将输入和模型
的权重(
`w`
)相乘,再加上偏移(
`b`
)
:
```
{.python .input n=8}
```
{.python .input n=8}
def net(X):
def net(X):
...
@@ -101,13 +113,13 @@ def net(X):
...
@@ -101,13 +113,13 @@ def net(X):
```
{.python .input n=9}
```
{.python .input n=9}
def square_loss(yhat, y):
def square_loss(yhat, y):
# 注意这里我们把y变形成yhat的形状来避免
自动广播
# 注意这里我们把y变形成yhat的形状来避免
矩阵形状的自动转换
return (yhat - y.reshape(yhat.shape)) ** 2
return (yhat - y.reshape(yhat.shape)) ** 2
```
```
## 优化
## 优化
虽然线性回归有显试解,但绝大部分模型并没有。所以我们这里通过随机梯度下降来求解。每一步,我们将模型参数沿着梯度的反方向走特定距离,这个距离一般叫
学习率
。(我们会之后一直使用这个函数,我们将其保存在
[
utils.py
](
../utils.py
)
。)
虽然线性回归有显试解,但绝大部分模型并没有。所以我们这里通过随机梯度下降来求解。每一步,我们将模型参数沿着梯度的反方向走特定距离,这个距离一般叫
**学习率(learning rate)**
`lr`
。(我们会之后一直使用这个函数,我们将其保存在
[
utils.py
](
../utils.py
)
。)
```
{.python .input n=10}
```
{.python .input n=10}
def SGD(params, lr):
def SGD(params, lr):
...
@@ -117,25 +129,62 @@ def SGD(params, lr):
...
@@ -117,25 +129,62 @@ def SGD(params, lr):
## 训练
## 训练
现在我们可以开始训练了。训练通常需要迭代数据数次,一次迭代里,我们每次随机读取固定数个数据点,计算梯度并更新模型参数。
现在我们可以开始训练了。训练通常需要迭代数据数次,在这里使用
`epochs`
表示迭代总次数;一次迭代中,我们每次随机读取固定数个数据点,计算梯度并更新模型参数。
```
{.python .input}
# 模型函数
def real_fn(X):
return 2 * X[:, 0] - 3.4 * X[:, 1] + 4.2
# 绘制损失随训练次数降低的折线图,以及预测值和真实值的散点图
def plot(losses, X, sample_size=100):
xs = list(range(len(losses)))
f, (fg1, fg2) = plt.subplots(1, 2)
fg1.set_title('Loss during training')
fg1.plot(xs, losses, '-r')
fg2.set_title('Estimated vs real function')
fg2.plot(X[:sample_size, 1].asnumpy(),
net(X[:sample_size, :]).asnumpy(), 'or', label='Estimated')
fg2.plot(X[:sample_size, 1].asnumpy(),
real_fn(X[:sample_size, :]).asnumpy(), '*g', label='Real')
fg2.legend()
plt.show()
```
```
{.python .input n=11}
```
{.python .input n=11}
epochs = 5
epochs = 5
learning_rate = .001
learning_rate = .001
for e in range(epochs):
niter = 0
losses = []
moving_loss = 0
smoothing_constant = .01
# 训练
for e in range(epochs):
total_loss = 0
total_loss = 0
for data, label in data_iter():
for data, label in data_iter():
with autograd.record():
with autograd.record():
output = net(data)
output = net(data)
loss = square_loss(output, label)
loss = square_loss(output, label)
loss.backward()
loss.backward()
SGD(params, learning_rate)
SGD(params, learning_rate)
total_loss += nd.sum(loss).asscalar()
total_loss += nd.sum(loss).asscalar()
print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))
# 记录每读取一个数据点后,损失的移动平均值的变化;
niter +=1
curr_loss = nd.mean(loss).asscalar()
moving_loss = (1 - smoothing_constant) * moving_loss + (smoothing_constant) * curr_loss
# correct the bias from the moving averages
est_loss = moving_loss/(1-(1-smoothing_constant)**niter)
if (niter + 1) % 100 == 0:
losses.append(est_loss)
print("Epoch %s, batch %s. Moving avg of loss: %s. Average loss: %f" % (e, niter, est_loss, total_loss/num_examples))
plot(losses, X)
```
```
训练完成后
我们可以比较学到
的参数和真实参数
训练完成后
,我们可以比较学得
的参数和真实参数
```
{.python .input n=12}
```
{.python .input n=12}
true_w, w
true_w, w
...
@@ -147,7 +196,7 @@ true_b, b
...
@@ -147,7 +196,7 @@ true_b, b
## 结论
## 结论
我们现在看到
仅仅使用NDArray和autograd我们可以很容易地实现一个
模型。
我们现在看到
,仅仅是使用NDArray和autograd就可以很容易实现的一个模型。在接下来的教程里,我们会在此基础上,介绍更多现代神经网络的知识,以及怎样使用少量的MXNet代码实现各种复杂的
模型。
## 练习
## 练习
...
...
img/onelayer.png
0 → 100644
浏览文件 @
bd0950a1
10.9 KB
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录