deeplearning_class1:线性回归&softmax与分类模型&多层感知机

时光总嘲笑我的痴心妄想 提交于 2020-02-15 11:18:36

1.线性回归

线性回归的基本公式是:Y=WX+bY=WX+b
在计算线性回归中,我们需要求解的就是误差最小时的线性回归方程,为此,需要了解损失函数。这里我们以差平方来表示误差,有l(i)(w,b)=12(y^y(i))2l^{(i)}(w,b)=\frac{1}{2}(\hat{y}-y^{(i)})^2
损失函数以平均误差和来表示:L(w,b)=1ni=1nl(i)(w,b)L(w,b) = \frac{1}{n}\sum^{n}_{i=1}l^{(i)}(w,b)
所谓线性回归模型的训练,就是指训练以数据,得到误差最小的线性回归方程,通俗的讲,就是一次次的向线性回归模型中带入训练集,通过计算误差,来调整线性回归模型的wwbb
这里,我们采用随机梯度下降的方法来调整ww,bb
(w,b)(w,b)ηβiβ(w,b)l(i)(w,b)(w,b)\leftarrow (w,b)-\frac{\eta}{\beta}\sum_{i\in \beta}\partial_{(w,b)}l^{(i)}(w,b)
式中:
η\eta代表学习率,可以达标每次调整(w,b)(w,b)值的大小,当然,调整的量不仅仅由η\eta决定,还由偏导数的值决定。
β\beta代表批量大小。

1.1 矢量计算

在模型训练时通常使用矢量计算,因为矢量计算速度远比使用for循环速度快。

1.2 线性回归模型构建

这里我们创造一个数据集,用来进行训练线性回归模型。其中,我们数据集样本数量为1000,模型为:
y=w1x1+w2x2+by = w_1x_1 + w_2x_2 + b

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

# 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

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)

# 读取数据集
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
# 初始化模型参数
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): 
    return (y_hat - y.view(y_hat.size())) ** 2 / 2
# 定义优化函数
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
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()))
print(w, true_w, b, true_b)

1.3利用pytorch简洁实现

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

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)
# 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])

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

2. softmax和分类模型

线性回归可用于连续值得预测和分类,softmax可用于离散值的分类问题,例如:
在这里插入图片描述
如图,softmax回归是一个单层神经网络
在这里插入图片描述
因为输出值的大小会影响最终的分类情况,所以,需要对输出值进行变换:在这里插入图片描述
softmax回归的权重w和偏差b非别为:在这里插入图片描述
高和宽分别为2个像素的图像样本i的特征为:
在这里插入图片描述
输出层的输出为:在这里插入图片描述
预测为狗、猫或鸡的概率分布为
在这里插入图片描述
foftmax回归对样本i分类的表达式:在这里插入图片描述
交叉熵损失函数定义:在这里插入图片描述
其中 𝚯 代表模型参数。同样地,如果每个样本只有一个标签,那么交叉熵损失可以简写成 ℓ(𝚯)=−(1/𝑛)∑𝑛𝑖=1log𝑦̂ (𝑖)𝑦(𝑖) 。从另一个角度来看,我们知道最小化 ℓ(𝚯) 等价于最大化 exp(−𝑛ℓ(𝚯))=∏𝑛𝑖=1𝑦̂ (𝑖)𝑦(𝑖) ,即最小化交叉熵损失函数等价于最大化训练数据集所有标签类别的联合预测概率。

  • Fashion-MNIST训练集和读取数据
    本次练习中,我们需要使用torchvision包,它是服务于PyTorch深度学习框架的,主要用来构建计算机视觉模型。torchvision主要由以下几部分构成:

torchvision.datasets: 一些加载数据的函数及常用的数据集接口;
torchvision.models: 包含常用的模型结构(含预训练模型),例如AlexNet、VGG、ResNet等;
torchvision.transforms: 常用的图片变换,例如裁剪、旋转等;
torchvision.utils: 其他的一些有用的方法。

# 加载各种包或者模块
import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l

# 初始化参数和获取数据
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

# 定义网络模型
num_inputs = 784
num_outputs = 10

class LinearNet(nn.Module):
    def __init__(self, num_inputs, num_outputs):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(num_inputs, num_outputs)
    def forward(self, x): # x 的形状: (batch, 1, 28, 28)
        y = self.linear(x.view(x.shape[0], -1))
        return y
    
# net = LinearNet(num_inputs, num_outputs)

class FlattenLayer(nn.Module):
    def __init__(self):
        super(FlattenLayer, self).__init__()
    def forward(self, x): # x 的形状: (batch, *, *, ...)
        return x.view(x.shape[0], -1)

from collections import OrderedDict
net = nn.Sequential(
        # FlattenLayer(),
        # LinearNet(num_inputs, num_outputs) 
        OrderedDict([
           ('flatten', FlattenLayer()),
           ('linear', nn.Linear(num_inputs, num_outputs))]) # 或者写成我们自己定义的 LinearNet(num_inputs, num_outputs) 也可以
        )
# 初始化模型参数
init.normal_(net.linear.weight, mean=0, std=0.01)
init.constant_(net.linear.bias, val=0)

# 定义损失函数
loss = nn.CrossEntropyLoss() # 下面是他的函数原型
# class torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

# 定义优化函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.1) # 下面是函数原型
# class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)

# 训练
num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)

3.多层感知机

在这里插入图片描述
如图,多层感知机是多层神经网络模型,与前面的模型不同,多层感知机中含有隐藏层,上图中,隐藏层有五个隐藏单元。
在多层感知机和大多数多层神经网络中,都需要用到激活函数,激活函数是将输出转换为0,1的函数。常见的激活函数有:

  • RELU函数:
    在这里插入图片描述
  • sigmoid函数:
    在这里插入图片描述
  • tanh函数:
    在这里插入图片描述
import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l

# 初始化模型和各个参数
num_inputs, num_outputs, num_hiddens = 784, 10, 256
    
net = nn.Sequential(
        d2l.FlattenLayer(),
        nn.Linear(num_inputs, num_hiddens),
        nn.ReLU(),
        nn.Linear(num_hiddens, num_outputs), 
        )
    
for params in net.parameters():
    init.normal_(params, mean=0, std=0.01)

# 训练
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')
loss = torch.nn.CrossEntropyLoss()

optimizer = torch.optim.SGD(net.parameters(), lr=0.5)

num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)

pyorch实现真的好方便,咳咳。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!