task1

Task1-1 线型回归笔记

一、线型回归模型讲解

1、什么是线型模型

表示数据可以用线型关系来描述。公式化的情况下为y=wx+b。建模的过程,就是求取w,b的过程。
但由于真实数据存在偏差,无法获得无偏估计,只能寻找一个偏差最小的模型。在这里插入图片描述

2、线型模型的求解

基本概念:
数据集=训练集+测试集=样本+标签
样本用特征表示(房子与房价相关的特征有面积,新旧等)
模型希望能建立这些特征和房价之间的关系,使得预测值和真实值之间的误差最小,这样模型预测出的房价(预测值)和实际的房价(真实值)就最接近

损失函数

在模型训练中,我们需要衡量价格预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数。 它在评估索引为 i i i 的样本误差的表达式为

l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 , l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2, l(i)(w,b)=21(y^(i)y(i))2,

L ( w , b ) = 1 n ∑ i = 1 n l ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w ⊤ x ( i ) + b − y ( i ) ) 2 . L(\mathbf{w}, b) =\frac{1}{n}\sum_{i=1}^n l^{(i)}(\mathbf{w}, b) =\frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2. L(w,b)=n1i=1nl(i)(w,b)=n1i=1n21(wx(i)+by(i))2.

优化函数

当损失函数无法之间求解时,需要进行迭代求解,逼近真实值。在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:先选取一组模型参数的初始值,如随机选取;接下来对参数进行多次迭代,使每次迭代都可能降低损失函数的值。在每次迭代中,先随机均匀采样一个由固定数目训练数据样本所组成的小批量(mini-batch) B \mathcal{B} B,然后求小批量中数据样本的平均损失有关模型参数的导数(梯度),最后用此结果与预先设定的一个正数的乘积作为模型参数在本次迭代的减小量。

( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) (\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b) (w,b)(w,b)BηiB(w,b)l(i)(w,b)

学习率: η \eta η代表在每次优化中,能够学习的步长的大小
批量大小: B \mathcal{B} B是小批量计算中的批量大小batch size

总结一下,优化函数的有以下两个步骤:

  • (i)初始化模型参数,一般来说使用随机初始化;
  • (ii)我们在数据上迭代多次,通过在负梯度方向移动参数来更新每个参数。

二 、线型回归代码讲解

1、矢量计算

矢量计算速度较快
向量相加的一种方法是,将这两个向量按元素逐一做标量加法。c[i] = a[i] + b[i]
向量相加的另一种方法是,将这两个向量直接做矢量加法。d = a + b

2、 线性回归模型从零开始的实现

头文件
# import packages and modules
%matplotlib inline
import torch
from IPython import display
from matplotlib import pyplot as plt
import numpy as np
import random

print(torch.__version__)
生成数据

假设模型参数w和b生成数据,为了使数据符合真实情况,添加波动
生成一个1000个样本的数据集,下面是用来生成数据的线性关系:

p r i c e = w a r e a ⋅ a r e a + w a g e ⋅ a g e + b \mathrm{price} = w_{\mathrm{area}} \cdot \mathrm{area} + w_{\mathrm{age}} \cdot \mathrm{age} + b price=wareaarea+wageage+b

# set input feature number 特征数
num_inputs = 2
# set example number样本数
num_examples = 1000

# set true weight and bias in order to generate corresponded label
true_w = [2, -3.4]
true_b = 4.2
#生成1000x2个随机数,作为特征值
features = torch.randn(num_examples, num_inputs,
                      dtype=torch.float32)
#根据w和b的值,生成特征相应的标签
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)
                   

使用图像展示数据

#数据特征[1]和标签之间的关系
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1);
读取数据

将数据集分成小批

#
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)  # random read 10 samples
    for i in range(0, num_examples, batch_size):
        j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # the last time may be not enough for a whole 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, '\n', y)
    break
  • 程序执行顺序:
    for从函数data_iter中获得可迭代对象,调用next方法。
    data_iter运行至 yield处,并return,此处 yield相当于return
    for将值赋予X,y后,进行下一轮迭代,继续data_iter中的for循环

  • 相关知识:
    生成器: 带yield的函数是一个生成器(生成器是一类特殊的迭代器),而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。

    for item in Iterable循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
    参考文献:
    迭代器 iter()函数与next()函数 for…in…循环的本质
    理解 Python 中的 for 循环:有关于for循环调用next方法的步骤

初始化模型参数
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)

所有的tensor都有.requires_grad属性,可以设置这个属性,之后可以调用backward()求导。

定义模型

定义用来训练参数的训练模型:
p r i c e = w a r e a ⋅ a r e a + w a g e ⋅ a g e + b \mathrm{price} = w_{\mathrm{area}} \cdot \mathrm{area} + w_{\mathrm{age}} \cdot \mathrm{age} + b price=wareaarea+wageage+b

def linreg(X, w, b):
    return torch.mm(X, w) + b
定义损失函数

我们使用的是均方误差损失函数:
l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 , l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2, l(i)(w,b)=21(y^(i)y(i))2,

def squared_loss(y_hat, y): 
    return (y_hat - y.view(y_hat.size())) ** 2 / 2
定义优化函数

在这里优化函数使用的是小批量随机梯度下降:

( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) (\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b) (w,b)(w,b)BηiB(w,b)l(i)(w,b)

  def sgd(params, lr, batch_size): 
    for param in params:
        param.data -= lr * param.grad / batch_size # ues .data to operate param without gradient track
训练

当数据集、模型、损失函数和优化函数定义完了之后就可来准备进行模型的训练了。

# super parameters init
lr = 0.03#学习率
num_epochs = 5#训练周期

net = linreg
loss = squared_loss

# training
#进行5轮训练,每轮训练都是分批求解,5轮结果正确率求平均
for epoch in range(num_epochs):  # training repeats num_epochs times
    # in each epoch, all the samples in dataset will be used once
    
    # X is the feature and y is the label of a batch sample
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y).sum()  
        # calculate the gradient of batch sample loss 
        l.backward()#计算梯度  
        # using small batch random gradient descent to iter model parameters模型求解
        sgd([w, b], lr, batch_size)  
        # reset parameter gradient梯度清零
        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()))

自动求导:这里l.backward()获得loss对于w和b的导数,x.grad获取求得的导数

3、pytorch简洁实现

import torch
from torch import nn
import numpy as np
torch.manual_seed(1)

print(torch.__version__)
torch.set_default_tensor_type('torch.FloatTensor')
生成数据集

在这里生成数据集跟从零开始的实现中是完全一样的。

num_inputs = 2
num_examples = 1000

true_w = [2, -3.4]
true_b = 4.2

features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
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.float)
读取数据集
import torch.utils.data as Data

batch_size = 10

# combine featues and labels of dataset
dataset = Data.TensorDataset(features, labels)

# put dataset into DataLoader
data_iter = Data.DataLoader(
    dataset=dataset,            # torch TensorDataset format
    batch_size=batch_size,      # mini batch size
    shuffle=True,               # whether shuffle the data or not
    num_workers=2,              # read data in multithreading线程数
)
for X, y in data_iter:
    print(X, '\n', y)
    break
定义模型

定义线网络的类,网络结构和传播方式

class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()      # call father function to init 
        self.linear = nn.Linear(n_feature, 1)  # function prototype: `torch.nn.Linear(in_features, out_features, bias=True)`

    def forward(self, x):
        y = self.linear(x)
        return y
    
net = LinearNet(num_inputs)
print(net)
LinearNet(
  (linear): Linear(in_features=2, out_features=1, bias=True)
)
# ways to init a multilayer network生成多层网络的方法
# method one
net = nn.Sequential(
    nn.Linear(num_inputs, 1)
    # other layers can be added here
    )

# method two
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))
# net.add_module ......

# method three:将神经网络层放入字典中传入
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
          ('linear', nn.Linear(num_inputs, 1))
          # ......
        ]))

print(net)#全部神经网络
print(net[0])#第一层
初始化模型参数

使用init进行初始化

# 2. 正态分布 - N(mean, std)
# torch.nn.init.normal_(tensor, mean=0, std=1)
# 3. 常数 - 固定值 val
# torch.nn.init.constant_(tensor, val)
nn.init.constant_(w, 0.3)
from torch.nn import init

init.normal_(net[0].weight, mean=0.0, std=0.01)
init.constant_(net[0].bias, val=0.0)  # or you can use `net[0].bias.data.fill_(0)` to modify it directly
定义损失函数
for param in net.parameters():
    print(param)
loss = nn.MSELoss()    # nn built-in squared loss function
                       # function prototype: `torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
                       
定义优化函数
import torch.optim as optim

optimizer = optim.SGD(net.parameters(), lr=0.03)   # built-in random gradient descent function随机梯度下降
print(optimizer)  # function prototype: `torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)`

训练

两个循环,周期和batch, y.view和numpy里的reshape是一样的,使数据横向排列

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() # reset gradient, equal to net.zero_grad()
        l.backward()#反向传播计算梯度
        optimizer.step()
    print('epoch %d, loss: %f' % (epoch, l.item()))#每个周期进行一个输出
# result comparision
dense = net[0]
print(true_w, dense.weight.data)
print(true_b, dense.bias.data)

task1-2 softmax和分类模型

线型回归和softmax的区别:连续和离散
softmax:输出为每种类别的置信度,输出数=标签类别数
线型回归:预测值
Image Name
softmax将输出值变换成值为正且和为1的概率分布:

y ^ 1 , y ^ 2 , y ^ 3 = softmax ( o 1 , o 2 , o 3 ) \hat{y}_1, \hat{y}_2, \hat{y}_3 = \text{softmax}(o_1, o_2, o_3) y^1,y^2,y^3=softmax(o1,o2,o3)

其中

y ^ 1 = exp ⁡ ( o 1 ) ∑ i = 1 3 exp ⁡ ( o i ) , y ^ 2 = exp ⁡ ( o 2 ) ∑ i = 1 3 exp ⁡ ( o i ) , y ^ 3 = exp ⁡ ( o 3 ) ∑ i = 1 3 exp ⁡ ( o i ) . \hat{y}1 = \frac{ \exp(o_1)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}2 = \frac{ \exp(o_2)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}3 = \frac{ \exp(o_3)}{\sum_{i=1}^3 \exp(o_i)}. y^1=i=13exp(oi)exp(o1),y^2=i=13exp(oi)exp(o2),y^3=i=13exp(oi)exp(o3).

softmax回归对样本 i i i分类的矢量计算表达式为

o ( i ) = x ( i ) W + b , y ^ ( i ) = softmax ( o ( i ) ) . \begin{aligned} \boldsymbol{o}^{(i)} &= \boldsymbol{x}^{(i)} \boldsymbol{W} + \boldsymbol{b},\\ \boldsymbol{\hat{y}}^{(i)} &= \text{softmax}(\boldsymbol{o}^{(i)}). \end{aligned} o(i)y^(i)=x(i)W+b,=softmax(o(i)).

交叉熵损失函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值