pytorch入门(一):基本概念、模型训练与保存、优化器

如何将list转为Tensor

torch.stack(myls, dim=1)

matplotlib显示mnist数据集图片

import torch
import torchvision
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')  # 不加这一行的话pycharm不显示动态图

# Mnist digits dataset
train_data = torchvision.datasets.MNIST(
    root='./mnist/',
    train=True,                                     # this is training data
    transform=torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to
                                                    # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
    download=True,                        # download it if you don't have it
)

print(train_data.train_data.size())
print(train_data.train_labels.size())
plt.imshow(train_data.train_data[2].numpy(),cmap='gray')
plt.title('%d'%train_data.train_labels[2])
plt.show()

什么是深度学习

深度学习是机器学习中的神经网络的延伸,它将这门学问发扬光大!

什么是神经网络

计算机神经网络是模仿生物神经网络的一种运算模型。神经网络有输入层、隐藏层和输出层,通过输出层可以直观看到计算机的判断。

在这里插入图片描述

我们需要许多张带有标签的数据,给他看数据,首先会给我们不成熟的答案,通过一张张辨识,错误答案会反向传播让神经元的激活函数的参数进行调整,使得部分神经元变得活跃或迟钝。

黑盒

其中,输入层可以是将原数据进行处理之后的数据,称为特征,加工后的数据称为代表特征。

依次打开黑盒,就相当于黑盒不存在,与其说是黑盒对数据进行加工,不如说是由一种代表特征转化为了另一种代表特征。

在这里插入图片描述

我们可以试用神经网络得到的代表特征来进行迁移学习

在这里插入图片描述

什么是梯度下降

神经网络是梯度下降法的一个分支,得到误差函数,通过梯度下降的方式,得到误差最小(在运动就会上升)的参数,即极小值。下面是一个简化的误差曲线

在这里插入图片描述

但是,往往我们的得到的误差曲线不止有一个极小值。

在这里插入图片描述

不同的W初始化的位置会带来不同的下降区域,不同的下降区域会带来不同的W的解,我们可以得到全局最优解和局部最优解(通常会得到局部最优解),但是不用怕,因为计算机可以让我们的局部最优解变得足够优秀,可以用它很出色的完成手中的任务。

激励函数(activation funcations)

生活中很多模型都不是线性的,我们可以使用激励函数将我们的线性模型变为非线性模型

在这里插入图片描述

AF就是一个非线性方程,常见的分为三种,我们也可以自己定义激励函数,但必须是可以微分的,因为在进行误差反向传播的时候,只有可微分的激励函数才可以将误差反向传播回去。

在这里插入图片描述

在这里插入图片描述

当我们只有隐藏层只有一两层的时候,使用任意的激励函数随便掰弯都可以,影响不大,但是隐藏层很多的时候不能随意选择,可能会引起梯度爆炸,梯度消失等问题。

在少量层中使用激励函数推荐如下:

  • 卷积神经网络:relu
  • 循环神经网络:relu或tanh

回归(Regression)

我们的神经网络可以分为两种类型,一种叫做回归,一种叫做分类。

  • “回归”,大概的意思就是事物总是倾向于朝着某种“平均”发展,也可以说是回归于事物本来的面目。

  • “分类”,就是将数据进行分类。。。

下面我们做一个回归模型

先看看数据:

import torch

import torch.nn.functional as F
import matplotlib.pyplot as plt

# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
# 添加噪点
y = x.pow(2) + 0.2*torch.rand(x.size())

plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()

构建模型(图):

class Net(torch.nn.Module):
    def __init__(self,n_feature,n_hidden,n_output):  # 搭建我们的层所需要的信息
        super(Net,self).__init__()
        self.hidden = torch.nn.Linear(n_feature,n_hidden)  # 一个隐藏层。包含的信息是有多少个输入和输出
        self.predict = torch.nn.Linear(n_hidden,n_output)  # 因为我们是预测y的值,这里n_out可以直接写成1


    def forward(self,x):  # 神经网络前向传递的一个过程,搭建神经网络
        x = F.relu(self.hidden(x))  # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
        y = self.predict(x)  # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
        return y

训练、优化模型:

net = Net(1,10,1)
# print(net)

# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)  # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss()  # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
    # 预测
    prediction = net(x)
    # 计算损失
    loss = loss_func(prediction,y)  # 计算预测值与真实值的误差,预测值在前,真实值在后
    # 开始优化
    optimizer.zero_grad()  # 先将神经网络的参数的梯度降为0
    loss.backward()  # 反向传递,给每个节点计算梯度
    optimizer.step()
    # 可视化训练过程
    if t%5 == 0:
        plt.cla()
        plt.scatter(x.data.numpy(),y.data.numpy())
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
        plt.text(0.5,0,'loss=%.4f'%loss.item(),fontdict={'size':20,'color':'red'})
        plt.pause(0.1)
plt.ioff()
plt.show()

代码汇总:

import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')  # 不加这一行的话pycharm不显示动态图

# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
# 添加噪点
y = x.pow(2) + 0.2*torch.rand(x.size())
plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()

class Net(torch.nn.Module):
    def __init__(self,n_feature,n_hidden,n_output):  # 搭建我们的层所需要的信息
        super(Net,self).__init__()
        self.hidden = torch.nn.Linear(n_feature,n_hidden)  # 一个隐藏层。包含的信息是有多少个输入和输出
        self.predict = torch.nn.Linear(n_hidden,n_output)  # 因为我们是预测y的值,这里n_out可以直接写成1


    def forward(self,x):  # 神经网络前向传递的一个过程,搭建神经网络
        x = F.relu(self.hidden(x))  # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
        y = self.predict(x)  # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
        return y
    
net = Net(1,10,1)
# print(net)
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)  # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss()  # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
    # 预测
    prediction = net(x)
    # 计算损失
    loss = loss_func(prediction,y)  # 计算预测值与真实值的误差,预测值在前,真实值在后
    # 开始优化
    optimizer.zero_grad()  # 先将神经网络的参数的梯度降为0
    loss.backward()  # 反向传递,给每个节点计算梯度
    optimizer.step()
    # 可视化训练过程
    if t%5 == 0:
        plt.cla()
        plt.scatter(x.data.numpy(),y.data.numpy())
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
        plt.text(0.5,0,'loss=%.4f'%loss.item(),fontdict={'size':20,'color':'red'})
        plt.pause(0.1)
plt.ioff()
plt.show()

分类(Classification)

多分类返回的数据格式:数字1在哪个位置,就被规定在哪一类了。

和回归模型差不多,多分类的损失函数换为CrossEntropyLoss,他计算的是概率误差

import torch

import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')

n_data = torch.ones(100,2)  # 二维数据。100个数字分开,得到50行
# print(n_data)
x0 = torch.normal(2*n_data,1)
y0 = torch.zeros(100)
x1 = torch.normal(-2*n_data,1)
y1 = torch.ones(100)
x = torch.cat((x0,x1),0).type(torch.FloatTensor)  # 数据
y = torch.cat((y0,y1),).type(torch.LongTensor)  # 标签

# plt.scatter(x.data.numpy()[:,0],x.data.numpy()[:,1],c=y.data.numpy(),s=100,lw=0,cmap=)
# plt.show()

class Net(torch.nn.Module):
    def __init__(self,n_feature,n_hidden,n_output):  # 搭建我们的层所需要的信息
        super(Net,self).__init__()
        self.hidden = torch.nn.Linear(n_feature,n_hidden)  # 一个隐藏层。包含的信息是有多少个输入和输出
        self.predict = torch.nn.Linear(n_hidden,n_output)  # 因为我们是预测y的值,这里n_out可以直接写成1


    def forward(self,x):  # 神经网络前向传递的一个过程,搭建神经网络
        x = F.relu(self.hidden(x))  # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
        y = self.predict(x)  # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
        return y

net = Net(2,10,2)  # 输入信息有xy两个特征,输出为2分类

# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)  # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.CrossEntropyLoss()  # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
    # 预测
    out = net(x)
    # 计算损失
    loss = loss_func(out,y)  # 计算预测值与真实值的误差,预测值在前,真实值在后
    # 开始优化
    optimizer.zero_grad()  # 先将神经网络的参数的梯度降为0
    loss.backward()  # 反向传递,给每个节点计算梯度
    optimizer.step()

    if t%2 == 0:
        plt.cla()
        prediction = torch.max(F.softmax(out),1)[1]  # 使用F.softmax(out)将输出层的值转化为概率,概率相加为1。索引为0返回的是最大值,为1是index
        pred_y = prediction.data.numpy().squeeze()
        target_y = y.data.numpy()
        plt.scatter(x.data.numpy()[:,0],x.data.numpy()[:,1],c=pred_y,s=100,lw=0)
        accuracy = sum(pred_y == target_y)/200  # 准确率
        plt.text(1.5,-4,'Accuracy=%.4f'%loss.item(),fontdict={'size':20,'color':'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

使用Sequential快速搭建法

我们不用再手写class,可以使用Sequential快速搭建模型,下面是把上面回归模型修改了一下

import torch

import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')

# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y = x.pow(2) + 0.2*torch.rand(x.size())

# 搭建模型
net = torch.nn.Sequential(
    torch.nn.Linear(1,10),  # 线性模型
    torch.nn.ReLU(),  # 激励函数
    torch.nn.Linear(10,1),  # 线性模型
)

# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)  # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss()  # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
    # 预测
    prediction = net(x)
    # 计算损失
    loss = loss_func(prediction,y)  # 计算预测值与真实值的误差,预测值在前,真实值在后
    # 开始优化
    optimizer.zero_grad()  # 先将神经网络的参数的梯度降为0
    loss.backward()  # 反向传递,给每个节点计算梯度
    optimizer.step()

    if t%5 == 0:
        plt.cla()
        plt.scatter(x.data.numpy(),y.data.numpy())
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
        plt.text(0.5,0,'loss=%.4f'%loss.item(),fontdict={'size':20,'color':'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

保存提取神经网络

拟合线是平的的话就把lr改为0.4

import torch

import time
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')

torch.manual_seed(1)

# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)  # x data (tensor), shape=(100, 1)
y = x.pow(2) + 0.2*torch.rand(x.size())  # noisy y data (tensor), shape=(100, 1)

def save():  # 保存模型
    net = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),  # 激励函数
        torch.nn.Linear(10, 1),
    )
    # 使用优化器优化我们的参数
    optimizer = torch.optim.SGD(net.parameters(), lr=0.4)  # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
    # 怎么计算误差的一种手段
    loss_func = torch.nn.MSELoss()  # MSE是均方差,用均方差来处理回归问题就足以应对了
    # 开始训练,训练一百步
    for t in range(100):
        # 预测
        prediction = net(x)
        # 计算损失
        loss = loss_func(prediction, y)  # 计算预测值与真实值的误差,预测值在前,真实值在后
        # 开始优化
        optimizer.zero_grad()  # 先将神经网络的参数的梯度降为0
        loss.backward()  # 反向传递,给每个节点计算梯度
        optimizer.step()
    torch.save(net,'net.pkl')  # 保存的格式为pkl。保存整个图
    torch.save(net.state_dict(),'net_params.pkl')  # 保存神经网络的参数,速度较快

    plt.subplot(131)
    plt.title('NET1')
    plt.scatter(x.data.numpy(),y.data.numpy())
    plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)

def restore_net():  # 引入整个模型
    net2 = torch.load('net.pkl')
    prediction = net2(x)

    plt.subplot(132)
    plt.title('NET2')
    plt.scatter(x.data.numpy(),y.data.numpy())
    plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)


def restore_params():  # 只提取参数,速度稍微快点
    '''
    建立和net一模一样的神经网络,然后将参数复制到网络中去
    :return:
    '''
    net3 = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),  # 激励函数
        torch.nn.Linear(10, 1),
    )
    net3.load_state_dict(torch.load('net_params.pkl'))
    prediction = net3(x)

    plt.subplot(133)
    plt.title('NET3')
    plt.scatter(x.data.numpy(),y.data.numpy())
    plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)
    plt.show()
    
save()
restore_net()
restore_params()

批训练(minibatch training)

有时候数据非常大,我们不把所有的数据一起打包放到模型中去,通过拆分,每次都拿一小部分数据进行训练,提高训练速度。

注意,num_workers是多进程的意思,要在调用的时候放在main中,否则会一直递归。

import torch
import torch.utils.data as Data  # 引入批训练的模块

BATCH_SIZE = 5  # 每次训练5个
x = torch.linspace(1,10,10)
y = torch.linspace(10,1,10)


torch_dataset = Data.TensorDataset(x,y)
loader = Data.DataLoader(
    dataset=torch_dataset,
    batch_size=BATCH_SIZE,
    shuffle=True,
    num_workers=2  # 进程数量
)

if __name__ == '__main__':
    # 因为使用到了进程包,所以要在main中调用
    # 训练三回
    for epoch in range(3):
        # 开始训练我们的数据
        for step,(batch_x,batch_y) in enumerate(loader):
            # 模型训练
            print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
                  batch_x.numpy(), '| batch y: ', batch_y.numpy())

使用优化器加速神经网络训练

大多数的优化器是在更新神经网络的参数上动手脚,下图是常见的优化器。

我们可以使用SGD,将数据拆分,批量放入nn中训练。

Monentum意思是一直走下坡路,很快就能到最低点

AdaGrad是在学习率上动手脚,让他斜向前走。使得每一个参数更新,都会有不同的学习效率

Rmsprop是Monentum与AdaGrad的结合(实验证明,大多数情况下使用它可以又快又好的达到目标

在这里插入图片描述

四种optimizer优化器对比

在这里插入图片描述

import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')

torch.manual_seed(1)    # reproducible

LR = 0.01
BATCH_SIZE = 32
EPOCH = 12

# fake dataset
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))

# plot dataset
# plt.scatter(x.numpy(), y.numpy())
# plt.show()

# 使用上节内容提到的 data loader
torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(
    dataset=torch_dataset,
    batch_size=BATCH_SIZE,
    shuffle=True,
    num_workers=2,
)

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(1, 20)   # hidden layer
        self.predict = torch.nn.Linear(20, 1)   # output layer

    def forward(self, x):
        x = F.relu(self.hidden(x))      # activation function for hidden layer
        y = self.predict(x)             # linear output
        return y
# 为每个优化器创建一个 net
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]

opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSprop, opt_Adam]

loss_func = torch.nn.MSELoss()
losses_his = [[], [], [], []]   # 记录 training 时不同神经网络的 loss

if __name__ == '__main__':
    for epoch in range(EPOCH):
        print('Epoch: ', epoch)
        for step, (b_x, b_y) in enumerate(loader):
            # 对每个优化器, 优化属于他的神经网络
            for net, opt, l_his in zip(nets, optimizers, losses_his):
                output = net(b_x)              # get output for every net
                loss = loss_func(output, b_y)  # compute loss for every net
                opt.zero_grad()                # clear gradients for next train
                loss.backward()                # backpropagation, compute gradients
                opt.step()                     # apply gradients
                l_his.append(loss.data.numpy())     # loss recoder

    labels = ['SGD','Momentum','RMSprop','Adam']
    for i,l_his in enumerate(losses_his):
        plt.plot(l_his,label=labels[i])
    plt.legend()  # 放置图例
    plt.xlabel('Steps')
    plt.ylabel('Loss')
    plt.ylim((0,0.2))
    plt.show()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笼中小夜莺

嘿嘿嘿,请用金钱尽情地蹂躏我吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值