动手学深度学习(PyTorch)笔记二、深度学习基础——线性回归

动手学深度学习(PyTorch)代码笔记

记录pytorch用于深度学习的学习过程。

二、深度学习基础

1、线性回归

线性回归和softmax回归都是单层神经网络,用于解决回归问题。

(1)基本要素

1、模型定义

y ^ = x 1 w 1 + x 2 w 2 + b \hat y = x_1w_1 + x_2w_2 + b y^=x1w1+x2w2+b

2、模型训练
(1)训练数据
(2)损失函数

L = 1 n ∑ 1 2 ( y ^ ( i ) − y ( i ) ) 2 L = \frac 1 n\sum\frac 1 2(\hat y^{(i)} - y^{(i)})^2 L=n121(y^(i)y(i))2

(3)优化算法

解析解analytical solution:误差最小化问题的解可以直接用公式表达出来。

数值解numerical solution:只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。

​ 小批量梯度下降法mini-batch

3、模型预测

经过训练后,得到w1 w2 b。
y ^ = x 1 w 1 + x 2 w 2 + b \hat y = x_1w_1 + x_2w_2 + b y^=x1w1+x2w2+b
进行预测。

(2)表示方法

1、神经网络图

动手学深度学习(PyTorch)笔记二、深度学习基础——线性回归_第1张图片

2、矢量计算表达式

矢量计算比循环计算,快了1到2个数量级。所以尽可能用向量来计算。
y ^ = χ ω + b \hat y = \chi\omega + b y^=χω+b
相应的梯度下降迭代公式、损失函数均写成矢量。

2、线性回归代码实现

(1)生成数据集

import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random

num_inputs = 2          # 特征数
num_examples = 1000     # 样本数
true_w = [2, -3.4]      # 真实权重w
true_b = 4.2            # 真实偏差b
features = torch.randn(num_examples, num_inputs,    # 生成随机样本
                       dtype=torch.float32)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b   # 计算真实标签
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()),       # 加上随机噪声
                       dtype=torch.float32)

# 第一个样本:特征、标签
print(features[0], labels[0])


def use_svg_display():
    # 用矢量图显示
    display.set_matplotlib_formats('svg')


def set_figsize(figsize=(3.5, 2.5)):
    use_svg_display()
    # 设置图的尺寸
    plt.rcParams['figure.figsize'] = figsize

set_figsize()   # 设置好显示效果
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
plt.show()

动手学深度学习(PyTorch)笔记二、深度学习基础——线性回归_第2张图片

其余代码:

import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random

num_inputs = 2          # 特征数
num_examples = 1000     # 样本数
true_w = [2, -3.4]      # 真实权重w
true_b = 4.2            # 真实偏差b
features = torch.randn(num_examples, num_inputs,    # 生成随机样本 num_examples * num_inputs
                       dtype=torch.float32)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b   # 计算真实标签
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()),       # 加上随机噪声
                       dtype=torch.float32)

# 第一个样本:特征、标签
print(features[0], labels[0])


# def use_svg_display():
#     # 用矢量图显示
#     display.set_matplotlib_formats('svg')
#
#
# def set_figsize(figsize=(3.5, 2.5)):
#     use_svg_display()
#     # 设置图的尺寸
#     plt.rcParams['figure.figsize'] = figsize
#
# set_figsize()   # 设置好显示效果
# plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
# plt.show()



def data_iter(batch_size, features, labels):
    '''

    :param batch_size:  批量大小
    :param features:    样本集合
    :param labels:      标签
    :return:
    '''
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)  # 随机打乱list
    for i in range(0, num_examples, batch_size):
        j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)])     # 最后一次可能不足一个batch
        yield features.index_select(0, j), labels.index_select(0, j)


batch_size = 10

# for X, y in data_iter(batch_size, features, labels):
#     print(X, y)
#     break

w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b = torch.zeros(1, dtype=torch.float32)

w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)


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


# 定义损失函数
def squared_loss(y_hat, y):
    # 注意这里返回的是向量, 另外, pytorch里的MSELoss并没有除以 2
    return (y_hat - y.view(y_hat.size())) ** 2 / 2


# 定义优化算法:小批量随机梯度下降
def sgd(params, lr, batch_size):
    '''
    :param params:      权重参数
    :param lr:          学习率
    :param batch_size:  批量大小
    :return:
    '''
    for param in params:
        param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data


lr = 0.03           # 学习率
num_epochs = 3      # 迭代周期个数
net = linreg        # 网络模型
loss = squared_loss # 损失函数

for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
    # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)
    # X和y分别是小批量样本的特征和标签
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y).sum()  # l是有关小批量X和y的损失
        # l是向量,需要先sum()成标量再计算梯度
        l.backward()  # 小批量的损失对模型参数求梯度
        # 计算得到的梯度在w.grad、b.grad中
        sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降迭代模型参数

        # 不要忘了梯度清零
        w.grad.data.zero_()
        b.grad.data.zero_()
    # 一轮迭代完成/训练完一轮全部样本
    train_l = loss(net(features, w, b), labels)
    print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))

3、线性回归简易版代码

torch.utils.data模块提供了有关数据处理的工具

torch.nn模块定义了大量神经网络的层

torch.nn.init模块定义了各种初始化方法

torch.optim模块提供了很多常用的优化算法。

import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random
import torch.utils.data as Data
from torch import nn

from torch.nn import init
import torch.optim as optim

# 1、生成数据集
num_inputs = 2          # 特征数
num_examples = 1000     # 样本数
true_w = [2, -3.4]      # 真实权重w
true_b = 4.2            # 真实偏差b
features = torch.randn(num_examples, num_inputs,    # 生成随机样本 num_examples * num_inputs
                       dtype=torch.float32)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b   # 计算真实标签
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()),       # 加上随机噪声
                       dtype=torch.float32)

# 2、读取数据
batch_size = 10
# 将训练数据的特征和标签组合
dataset = Data.TensorDataset(features, labels)
# 随机读取小批量
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True)  # shuffle打乱样本顺序


# 3、定义模型
class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(n_feature, 1)

    # forward 定义前向传播
    def forward(self, x):
        y = self.linear(x)
        return y


net = LinearNet(num_inputs)
# print(net)  # 使用print可以打印出网络的结构

# 4、初始化参数模型
init.normal_(net.linear.weight, mean=0, std=0.01)   # 正态分布
init.constant_(net.linear.bias, val=0)  # 0

# 5、定义损失函数
loss = nn.MSELoss()
# 6、定义优化函数
optimizer = optim.SGD(net.parameters(), lr=0.03)    # 梯度下降法 学习率0.03
# optimizer = optim.SGD([
#                 # 如果对某个参数不指定学习率,就使用最外层的默认学习率
#                 {'params': net.subnet1.parameters()}, # lr=0.03
#                 {'params': net.subnet2.parameters(), 'lr': 0.01}
#             ], lr=0.03)

# print(optimizer)
# 7、训练模型
num_epochs = 3  # 迭代轮数
for epoch in range(1, num_epochs + 1):
    for X, y in data_iter:
        output = net(X)
        l = loss(output, y.view(-1, 1))
        optimizer.zero_grad()   # 梯度清零,等价于net.zero_grad()
        l.backward()
        optimizer.step()
    print('epoch %d, loss: %f' % (epoch, l.item()))

print()
dense = net.linear
print(true_w, dense.weight)
print(true_b, dense.bias)

你可能感兴趣的:(PyTorch)