---
title: "torch实现线性回归模型"
description: "视频：08 线性回归 + 基础优化算法【动手学深度学习v2】"
canonical_url: "https://yangqiuyi.com/blog/suan-fa/ai/torch-shi-xian-xian-xing-hui-gui-mo-xing"
---

> Index of every page on this site: [llms.txt](https://yangqiuyi.com/llms.txt)

视频：[08 线性回归 + 基础优化算法【动手学深度学习v2】](https://www.bilibili.com/video/BV1PX4y1g7KC?p=3)

## 生成数据

```python
import torch

def synthetic_data(w, b, n_examples): # 生成数据集
    """生成 y = Xw + b + 噪声"""
    # X是符合均值为0，方差为1的正态分布， size为(n_examples, len(w))的矩阵
    X = torch.normal(0, 1, size=(n_examples, len(w)))
    y = torch.matmul(X, w) + b
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape([-1, 1])

true_w = torch.tensor([2, -4.2])
true_b = 3.6

features,labels = synthetic_data(true_w, true_b, 1000)
print("features: ", features.size())
print("labels: ", labels.size())
```

```txt
features:  torch.Size([1000, 2])
labels:  torch.Size([1000, 1])
```

## 生成批量数据(batch)

```python
import random
def data_iter(batch_size, features, labels): # 生成batch(批量)数据的方法
    num_examples = len(features)
    indices = list(range(num_examples)) # 生成样本的下标
    random.shuffle(indices) # 打乱下标
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(indices[i: min(i+batch_size, num_examples)])
        yield features[batch_indices], labels[batch_indices]
```

## 定义模型

```python
# 定义模型
def linreg(X, w, b):
    return torch.matmul(X, w) + b
```

## 随机梯度下降（SGD）

```python
def sgd(params, lr, batch_size):
    """小批量随机梯度下降方法"""
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size # 对参数进行优化
            '''
            因为是batch模式，一次输入了多个样本，所以param.grad是多个样本的累积梯度，
            因此要除以batch_size，才能得到正确的梯度
            参数的更新方法：
                参数 := 参数 - 学习率*梯度
            '''
            param.grad.zero_() # 梯度清零
```

## 均方损失函数

<span className="katex-display">
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics>
<mrow>
<mi>

L

</mi>

<mo>

=

</mo>

<mfrac>
<mn>

1

</mn>

<mn>

2

</mn>
</mfrac>

<mo>

∗

</mo>

<mo stretchy="false">

(

</mo>

<mover accent="true">
<mi>

y

</mi>

<mo>

^

</mo>
</mover>

<mo>

−

</mo>

<mi>

y

</mi>

<msup>
<mo stretchy="false">

)

</mo>

<mn>

2

</mn>
</msup>
</mrow>

<annotation encoding="application/x-tex">

L = \frac{1}{2} * (\hat{y} - y) ^ 2

</annotation>
</semantics>
</math>
</span>

<span className="katex-html" ariaHidden="true">
<span className="base">
<span className="strut" style="height:0.6833em;">



</span>

<span className="mord,mathnormal">

L

</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>

<span className="mrel">

=

</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:2.0074em;vertical-align:-0.686em;">



</span>

<span className="mord">
<span className="mopen,nulldelimiter">



</span>

<span className="mfrac">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:1.3214em;">
<span style="top:-2.314em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="mord">
<span className="mord">

2

</span>
</span>
</span>

<span style="top:-3.23em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="frac-line" style="border-bottom-width:0.04em;">



</span>
</span>

<span style="top:-3.677em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="mord">
<span className="mord">

1

</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.686em;">
<span>



</span>
</span>
</span>
</span>
</span>

<span className="mclose,nulldelimiter">



</span>
</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>

<span className="mbin">

∗

</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:1em;vertical-align:-0.25em;">



</span>

<span className="mopen">

(

</span>

<span className="mord,accent">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:0.6944em;">
<span style="top:-3em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="mord,mathnormal" style="margin-right:0.0359em;">

y

</span>
</span>

<span style="top:-3em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="accent-body" style="left:-0.1944em;">
<span className="mord">

^

</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.1944em;">
<span>



</span>
</span>
</span>
</span>
</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>

<span className="mbin">

−

</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:1.1141em;vertical-align:-0.25em;">



</span>

<span className="mord,mathnormal" style="margin-right:0.0359em;">

y

</span>

<span className="mclose">
<span className="mclose">

)

</span>

<span className="msupsub">
<span className="vlist-t">
<span className="vlist-r">
<span className="vlist" style="height:0.8641em;">
<span style="top:-3.113em;margin-right:0.05em;">
<span className="pstrut" style="height:2.7em;">



</span>

<span className="sizing,reset-size6,size3,mtight">
<span className="mord,mtight">

2

</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>

```python
def square_loss(y_hat, y):
    """均方损失函数"""
    return (y_hat - y) **2 / 2
```

## 训练模型

```python
EPOCHES = 10 # 数据集循环轮数
lr = 0.01 # learning rate 学习率
net = linreg # 线性回归模型
loss = square_loss
batch_size = 10
# 初始化参数
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

for i in range(EPOCHES):
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y)
        '''
        计算出来的loss的shape是(batch_size, 1)，不是一个标量
        因此我们需要对loss求sum，再求梯度
        '''
        l.sum().backward()
        sgd([w, b], lr, len(X))
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print("epoch %d, loss %f" % (i+1, float(train_l.mean())))
```

运行结果：

```txt
epoch 1, loss 2.347667
epoch 2, loss 0.326492
epoch 3, loss 0.045885
epoch 4, loss 0.006559
epoch 5, loss 0.000980
epoch 6, loss 0.000182
epoch 7, loss 0.000068
epoch 8, loss 0.000052
epoch 9, loss 0.000049
epoch 10, loss 0.000049
```

## 简洁实现

数据生成的方法是一样的，没有改动

```python
import torch

def synthetic_data(w, b, n_examples): # 生成数据集
    """生成 y = Xw + b + 噪声"""
    # X是符合均值为0，方差为1的正态分布， size为(n_examples, len(w))的矩阵
    X = torch.normal(0, 1, size=(n_examples, len(w)))
    y = torch.matmul(X, w) + b
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape([-1, 1])

true_w = torch.tensor([2, -4.2])
true_b = 3.6

features,labels = synthetic_data(true_w, true_b, 1000)
print("features: ", features.size())
print("labels: ", labels.size())
```

batch的生成方式有所不同，这里使用torch的`DataLoader`进行处理

```python
from torch.utils.data import TensorDataset, DataLoader

def load_array(data_arrays, batch_size, is_train=True):
    dataset = TensorDataset(*data_arrays)
    return DataLoader(dataset, batch_size, shuffle=is_train)

batch_size = 10
data_iter = load_array([features, labels], batch_size)
```

torch里的`nn.Linear`就是我们需要用的线性回归模型，也叫`全连接层`

```python
from torch import nn
net = nn.Sequential(nn.Linear(2, 1)) # 创建模型，用到了torch的Sequential类，可以理解成模型的容器，里面其实可以放多个模型，构成复杂神经网络
# 初始化模型
net[0].weight.data.normal_(0, 0.01) # 设置w
net[0].bias.data.fill_(0) # 设置b
```

训练模型

```python
EPOCHES = 10
for i in range(EPOCHES):
    for X, y in data_iter:
        l = loss(net(X), y)
        trainer.zero_grad()
        l.backward()
        trainer.step()
    l = loss(net(features), labels)
    print("epoch %d, loss %f" % (i+1, l))
```

## Sitemap

See the full [sitemap](https://yangqiuyi.com/sitemap.md) for all pages.
