ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

mofanpy-Pytorch神经网络学习笔记(二):建造第一个神经网络

2021-01-14 14:02:34  阅读:355  来源: 互联网

标签:plt nn self torch Pytorch 神经网络 mofanpy net data


Pytorch官网:https://pytorch.org/

建造第一个神经网络

目录

1 关系拟合 (回归)

(1)建立数据集

这里创建的是y = a * x^2 + b, 我们给 y 数据加上一点噪声来更加真实的展示它.

import torch
import matplotlib.pyplot as plt

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)
# 加了一点随机的偏置
# 画图
plt.scatter(x.data.numpy(), y.data.numpy())
plt.show()

在这里插入图片描述

Tips:torch.unsqueeze()
这个函数主要是对数据维度进行扩充,需要通过dim指定位置,给指定位置加上维数为1的维度。
例如,[1,2,3,4]维度为1,unsqueeze后的 [[1,2,3,4]] 维度变为2,torch只会处理二维数据。
这里torch.linspace(-1, 1, 100)得到的是开始端-1,结束端1,且分割成100个数据,生成线段,是一个一维列表,在位置dim为1增加一个维度,shape变成了100*1。
同样的,还有缩短维度的torch.squeeze()

(2)建立神经网络

建立一个神经网络我们可以直接运用 torch 中的体系.

  • 第一步: __ init __ ():先定义所有的层属性;
  • 第二步:forward(x):再一层层搭建层于层的关系链接(搭图).
import torch
import torch.nn.functional as F     # 激励函数都在这

class Net(torch.nn.Module):  # 继承 torch 的 Module
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()     # 继承 __init__ 功能
        # 定义每层用什么样的形式
        self.hidden = torch.nn.Linear(n_feature, n_hidden)   # 隐藏层线性输出
        self.predict = torch.nn.Linear(n_hidden, n_output)   # 输出层线性输出

    def forward(self, x):   # 这同时也是 Module 中的 forward 功能
        # 正向传播输入值, 神经网络分析出输出值
        x = F.relu(self.hidden(x))      # 激励函数(隐藏层的线性值)
        x = self.predict(x)             # 输出值
        return x

net = Net(n_feature=1, n_hidden=10, n_output=1)

print(net)  # net 的结构
Net(
  (hidden): Linear(in_features=1, out_features=10, bias=True)
  (predict): Linear(in_features=10, out_features=1, bias=True)
)

(3)训练网络

# optimizer 是训练的工具
optimizer = torch.optim.SGD(net.parameters(), lr=0.2)  # 传入 net 的所有参数, 学习率
loss_func = torch.nn.MSELoss()      # 预测值和真实值的误差计算公式 (均方差)

for t in range(100):
    prediction = net(x)     # 喂给 net 训练数据 x, 输出预测值

    loss = loss_func(prediction, y)     # 计算两者的误差

    optimizer.zero_grad()   # 清空上一步的残余更新参数值
    loss.backward()         # 误差反向传播, 计算参数更新值
    optimizer.step()        # 将参数更新值施加到 net 的 parameters 上

(4)可视化训练过程

import matplotlib.pyplot as plt

plt.ion()   # 画图
plt.show()

for t in range(200):

    ...
    loss.backward()
    optimizer.step()

    # 接着上面来
    if t % 5 == 0:
        # plot and show learning process
        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.data.numpy(), fontdict={'size': 20, 'color':  'red'})
        plt.pause(0.1)

(5)完整代码

框架:   
1.创建数据,x=... y=... 注意把数据变成Variable
2.创建网络,定义网络
	class Net(torch.nn.Module):        
	    def __init__():
	        super(Net, self).__init__()    
	        ... ...
	    def forward(self, x):
	        x =... ...
	        return x
	net = Net()   
3.训练网络
(1)定义优化器、损失函数
	optimizer = ...
	loss_func = ...
(2)循环训练
	for t in range(次数):
	    prediction = net(x)     
	    loss = loss_func(prediction, y)     
	    optimizer.zero_grad()   
	    loss.backward()          
	    optimizer.step() 
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt


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())                 # 加上噪点

x, y = Variable(x), Variable(y) # 把x,y变成Variable,神经网络只能输入Variable

plt.scatter(x.data.numpy(), y.data.numpy())   # 打印散点图
plt.show()


class Net(torch.nn.Module):        # 定义自己的网络Net,继承与Module
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()    # 继承一下,官方步骤必须要做
        self.hidden = torch.nn.Linear(n_feature, n_hidden)   # hidden layer,输入特征的个数,输出神经元的个数
        self.predict = torch.nn.Linear(n_hidden, n_output)   # output layer,输入隐藏层神经元个数

    def forward(self, x):
        x = F.relu(self.hidden(x))      # x先经过一个hidden layer加工一下,再激励函数激活
        x = self.predict(x)             # x通过输出层后输出,!tips1
        return x

net = Net(1, 10, 1)     # define the network
print(net)  # 打印显示一下网络结构

optimizer = torch.optim.SGD(net.parameters(), lr=0.2)     # 用SGD优化器优化神经网络,传入神经网络参数,学习率0.2
loss_func = torch.nn.MSELoss()  # 损失函数:MSELoss(mean squared loss)均方差

plt.ion()   # something about plotting

for t in range(200):
    prediction = net(x)     # 输入x到网络得到输出值

    loss = loss_func(prediction, y)     # 必须是predition在前,真实值在后

    # 以下三步就是优化的步骤
    optimizer.zero_grad()   # 每次训练完,下次训练时先清洗梯度为0
    loss.backward()          # 反向传递,给每一个节点计算出梯度
    optimizer.step()        # 用学习率优化梯度

    # 每学习5步就打印可视化一次
    if t % 5 == 0:
        # plot and show learning process
        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.data.numpy(), fontdict={'size': 20, 'color':  'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

在这里插入图片描述

Net(
  (hidden): Linear(in_features=1, out_features=10, bias=True)
  (predict): Linear(in_features=10, out_features=1, bias=True)
)

tip1: 为什么输出层不使用激励函数?因为输出结果往往是负无穷-正无穷的,激励函数会把数据截断。
tip2: 输出网络结构分析:hidden由一个输入到10个神经元,predict是从10个输出到一个神经元

在这里插入图片描述

2 区分类型 (分类)

(1)建立数据集

import torch
import matplotlib.pyplot as plt

# 假数据
n_data = torch.ones(100, 2)         # 数据的基本形态
x0 = torch.normal(2*n_data, 1)      # class0 x data (tensor), shape=(100, 2)
y0 = torch.zeros(100)               # class0 y data (tensor), shape=(100, 1)
x1 = torch.normal(-2*n_data, 1)     # class1 x data (tensor), shape=(100, 2)
y1 = torch.ones(100)                # class1 y data (tensor), shape=(100, 1)
x = torch.cat((x0, x1), 0).type(torch.FloatTensor)  # shape (200, 2) FloatTensor = 32-bit floating
y = torch.cat((y0, y1), ).type(torch.LongTensor)    # shape (200,) LongTensor = 64-bit integer

x, y = Variable(x), Variable(y)

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

在这里插入图片描述

Tips:
1.torch.normal()

torch.normal(mean, std, out=None),返回一个张量,张量里面的随机数是从相互独立的正态分布中随机生成的。
* mean (Tensor) – 每个元素的张量平均
* std (Tensor) – 每个单元标准差的张量
* out (Tensor, optional) – 输出张量
例子:在这里插入图片描述

2.torch.ones()
torch.ones(* sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False),返回一个填充标量值1的张量,其形状由变量参数大小定义。
例子:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrhwrxdA-1610603071363)(attachment:image.png)]

3.torch.cat()
torch.cat(tensors, dim=0, out=None),链接指定张量序列。Dim (int,optional)是张量连接的维度,例如:
在这里插入图片描述

(2)建立神经网络

这个和我们在前面 regression 的时候的神经网络基本没差. 差别是:1.输入有两个,因为每个数据由两个特征,x轴对应的特征和y轴对应的特征,2.输出有两个,因为要分两类。

import torch
import torch.nn.functional as F     # 激励函数都在这

class Net(torch.nn.Module):     # 继承 torch 的 Module
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()     # 继承 __init__ 功能
        self.hidden = torch.nn.Linear(n_feature, n_hidden)   # 隐藏层线性输出
        self.out = torch.nn.Linear(n_hidden, n_output)       # 输出层线性输出

    def forward(self, x):
        # 正向传播输入值, 神经网络分析出输出值
        x = F.relu(self.hidden(x))      # 激励函数(隐藏层的线性值)
        x = self.out(x)                 # 输出值, 但是这个不是预测值, 预测值还需要再另外计算
        return x

net = Net(n_feature=2, n_hidden=10, n_output=2) # 几个类别就几个 output

print(net)  # net 的结构
Net(
  (hidden): Linear(in_features=2, out_features=10, bias=True)
  (out): Linear(in_features=10, out_features=2, bias=True)
)

(3)训练网络

# optimizer 是训练的工具
optimizer = torch.optim.SGD(net.parameters(), lr=0.02)  # 传入 net 的所有参数, 学习率
loss_func = torch.nn.CrossEntropyLoss()
# MSE用在回归的损失计算,CrossRntropyLoss常用于分类尤其是二分类,他输出的是softmax也就是概率。

for t in range(100):
    out = net(x)     # 喂给 net 训练数据 x, 输出分析值

    loss = loss_func(out, y)     # 计算两者的误差

    optimizer.zero_grad()   # 清空上一步的残余更新参数值
    loss.backward()         # 误差反向传播, 计算参数更新值
    optimizer.step()        # 将参数更新值施加到 net 的 parameters 上

(4)可视化训练过程

import matplotlib.pyplot as plt

plt.ion()   # 画图
plt.show()

for t in range(100):

    ...
    loss.backward()
    optimizer.step()

    # 接着上面来
    if t % 2 == 0:
        plt.cla()
        # 过了一道 softmax 的激励函数后的最大概率才是预测值
        prediction = torch.max(F.softmax(out), 1)[1]
        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, cmap='RdYlGn')
        accuracy = sum(pred_y == target_y)/200.  # 预测中有多少和真实值一样
        plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color':  'red'})
        plt.pause(0.1)

plt.ioff()  # 停止画图
plt.show()

在这里插入图片描述

(5)完整代码

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

# torch.manual_seed(1)    # reproducible

# make fake data
n_data = torch.ones(100, 2)
x0 = torch.normal(2*n_data, 1)      # class0 x data (tensor), shape=(100, 2)
y0 = torch.zeros(100)               # class0 y data (tensor), shape=(100, 1)
x1 = torch.normal(-2*n_data, 1)     # class1 x data (tensor), shape=(100, 2)
y1 = torch.ones(100)                # class1 y data (tensor), shape=(100, 1)
x = torch.cat((x0, x1), 0).type(torch.FloatTensor)  # shape (200, 2) FloatTensor = 32-bit floating
y = torch.cat((y0, y1), ).type(torch.LongTensor)    # shape (200,) LongTensor = 64-bit integer

# The code below is deprecated in Pytorch 0.4. Now, autograd directly supports tensors
# x, y = Variable(x), Variable(y)

# plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=y.data.numpy(), s=100, lw=0, cmap='RdYlGn')
# 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)   # hidden layer
        self.out = torch.nn.Linear(n_hidden, n_output)   # output layer

    def forward(self, x):
        x = F.relu(self.hidden(x))      # activation function for hidden layer
        x = self.out(x)
        return x

net = Net(n_feature=2, n_hidden=10, n_output=2)     # define the network
print(net)  # net architecture

optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
loss_func = torch.nn.CrossEntropyLoss()  # the target label is NOT an one-hotted

plt.ion()   # something about plotting

for t in range(100):
    out = net(x)                 # input x and predict based on x
    loss = loss_func(out, y)     # must be (1. nn output, 2. target), the target label is NOT one-hotted

    optimizer.zero_grad()   # clear gradients for next train
    loss.backward()         # backpropagation, compute gradients
    optimizer.step()        # apply gradients

    if t % 2 == 0:
        # plot and show learning process
        plt.cla()
        prediction = torch.max(out, 1)[1]
        pred_y = prediction.data.numpy()
        target_y = y.data.numpy()
        plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=pred_y, s=100, lw=0, cmap='RdYlGn')
        accuracy = float((pred_y == target_y).astype(int).sum()) / float(target_y.size)
        plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color':  'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

3 快速搭建法

快速搭建一个回归网络,这里net1是之前的方法,net2是快速搭建法。

import torch
import torch.nn.functional as F


# replace following class code with an easy sequential network
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)   # hidden layer
        self.predict = torch.nn.Linear(n_hidden, n_output)   # output layer

    def forward(self, x):
        x = F.relu(self.hidden(x))      # activation function for hidden layer
        x = self.predict(x)             # linear output
        return x

net1 = Net(1, 10, 1)

# easy and fast way to build your network
net2 = torch.nn.Sequential(
    torch.nn.Linear(1, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1)
)

print(net1)     # net1 architecture
print(net2)     # net2 architecture
Net(
  (hidden): Linear(in_features=1, out_features=10, bias=True)
  (predict): Linear(in_features=10, out_features=1, bias=True)
)
Sequential(
  (0): Linear(in_features=1, out_features=10, bias=True)
  (1): ReLU()
  (2): Linear(in_features=10, out_features=1, bias=True)
)

net2把激励函数也一同纳入进去了, 但是 net1 中, 激励函数实际上是在 forward() 功能中才被调用的. 这也就说明了, 相比 net2, net1 的好处就是, 你可以根据你的个人需要更加个性化你自己的前向传播过程, 比如(RNN).

4 保存提取

训练好了一个模型, 我们当然想要保存它, 留到下次要用的时候直接提取直接用, 我们用回归的神经网络举例实现保存提取.

(1)保存

两种方法:

  • 方法一:保存整个网络:
    torch.save(net, ‘net.pkl’)
  • 方法二:只保存网络中的参数 (速度快, 占内存少):
    torch.save(net.state_dict(), ‘net_params.pkl’)
torch.manual_seed(1)    # reproducible

# 假数据
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():
    # save net1
    net1 = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),
        torch.nn.Linear(10, 1)
    )
    optimizer = torch.optim.SGD(net1.parameters(), lr=0.5)
    loss_func = torch.nn.MSELoss()

    for t in range(100):
        prediction = net1(x)
        loss = loss_func(prediction, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    # plot result
    plt.figure(1, figsize=(10, 3))
    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)

    # 两种保存方法:
    torch.save(net1, 'net.pkl')  # 方法一:保存整个网络
    torch.save(net1.state_dict(), 'net_params.pkl')   # 方法二:只保存网络中的参数 (速度快, 占内存少)

(2)提取网络

torch.load(‘net.pkl’)

def restore_net():
    # restore entire net1 to net2
    net2 = torch.load('net.pkl')
    prediction = net2(x)

(3)提取网络参数

net3.load_state_dict(torch.load(‘net_params.pkl’))

def restore_params():
    # 新建 net3
    net3 = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),
        torch.nn.Linear(10, 1)
    )

    # 将保存的参数复制到 net3
    net3.load_state_dict(torch.load('net_params.pkl'))
    prediction = net3(x)

(4)显示结果

# 保存 net1 (1. 整个网络, 2. 只有参数)
save()

# 提取整个网络
restore_net()

# 提取网络参数, 复制到新网络
restore_params()

在这里插入图片描述

5 批训练

DataLoader 是 torch 给你用来包装你的数据的工具. 所以要先将自己的 (numpy array 或其他) 数据形式装换成 Tensor, 然后再放进这个包装器中.
使用 DataLoader 有什么好处呢? 就是他们帮你有效地迭代数据, 举例:

import torch
import torch.utils.data as Data
torch.manual_seed(1)    # reproducible

BATCH_SIZE = 5      # 批训练的数据个数

x = torch.linspace(1, 10, 10)       # x data (torch tensor)
y = torch.linspace(10, 1, 10)       # y data (torch tensor)

# 先转换成 torch 能识别的 Dataset
torch_dataset = Data.TensorDataset(x, y)

# 把 dataset 放入 DataLoader
loader = Data.DataLoader(
    dataset=torch_dataset,      # torch TensorDataset format
    batch_size=BATCH_SIZE,      # mini batch size
    shuffle=True,               # 要不要打乱数据 (打乱比较好)
    num_workers=2,              # 多线程来读数据
)

for epoch in range(3):   # 训练所有!整套!数据 3 次
    for step, (batch_x, batch_y) in enumerate(loader):  # 每一步 loader 释放一小批数据用来学习
        # 假设这里就是你训练的地方...

        # 打出来一些数据
        print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
              batch_x.numpy(), '| batch y: ', batch_y.numpy())
Epoch:  0 | Step:  0 | batch x:  [ 5.  7. 10.  3.  4.] | batch y:  [6. 4. 1. 8. 7.]
Epoch:  0 | Step:  1 | batch x:  [2. 1. 8. 9. 6.] | batch y:  [ 9. 10.  3.  2.  5.]
Epoch:  1 | Step:  0 | batch x:  [ 4.  6.  7. 10.  8.] | batch y:  [7. 5. 4. 1. 3.]
Epoch:  1 | Step:  1 | batch x:  [5. 3. 2. 1. 9.] | batch y:  [ 6.  8.  9. 10.  2.]
Epoch:  2 | Step:  0 | batch x:  [ 4.  2.  5.  6. 10.] | batch y:  [7. 9. 6. 5. 1.]
Epoch:  2 | Step:  1 | batch x:  [3. 9. 1. 8. 7.] | batch y:  [ 8.  2. 10.  3.  4.]

可以看出, 每步都导出了5个数据进行学习. 然后每个 epoch 的导出数据都是先打乱了以后再导出.如果将BATCH_SIZE = 8, step=0 会导出8个数据, 但是, step=1 时数据库中的数据不够 8个, 这时, 在 step=1 就只给你返回这个 epoch 中剩下的数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4RMx3zfn-1610603071366)(attachment:image.png)]

6 加速神经网络训练

英文资料学习:http://sebastianruder.com/optimizing-gradient-descent/
包括以下几种模式:

  • Stochastic Gradient Descent (SGD)
  • Momentum
  • AdaGrad
  • RMSProp
  • Adam
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScMTXPIF-1610603071367)(attachment:image.png)]

(1)SGD随机梯度下降

最基础的方法就是 SGD , 如果用普通的训练方法, 就需要重复不断的把整套数据放入神经网络NN训练, 这样消耗的计算资源会很大.

如果把这些数据拆分成小批小批的, 然后再分批不断放入 NN 中计算, 这就是我们常说的 SGD 的正确打开方式了. 每次使用批数据, 虽然不能反映整体数据的情况, 不过却很大程度上加速了 NN 的训练过程, 而且也不会丢失太多准确率.

(2)Momentum 更新方法

传统的参数 W 的更新是把原始的 W 累加上一个负的学习率(learning rate) 乘以校正值 (dx). 这种方法可能会让学习过程曲折无比, 看起来像 喝醉的人回家时, 摇摇晃晃走了很多弯路.所以我们把这个人从平地上放到了一个斜坡上, 只要他往下坡的方向走一点点, 由于向下的惯性, 他不自觉地就一直往下走, 走的弯路也变少了. 这就是 Momentum 参数更新. 另外一种加速方法叫AdaGrad.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oTB9NfxD-1610603071368)(attachment:image.png)]

(3)AdaGrad 更新方法

这种方法是在学习率上面动手脚, 使得每一个参数更新都会有自己与众不同的学习率, 他的作用和 momentum 类似, 不过不是给喝醉酒的人安排另一个下坡, 而是给他一双不好走路的鞋子, 使得他一摇晃着走路就脚疼, 鞋子成为了走弯路的阻力, 逼着他往前直着走. 他的数学形式是这样的. 接下来又有什么方法呢? 如果把下坡和不好走路的鞋子合并起来, 是不是更好呢? 没错, 这样我们就有了 RMSProp 更新方法.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A7iD1QbH-1610603071369)(attachment:image.png)]

(4)RMSProp 更新方法

有了 momentum 的惯性原则 , 加上 adagrad 的对错误方向的阻力, 我们就能合并成这样. 让 RMSProp同时具备他们两种方法的优势. 不过细心的同学们肯定看出来了, 似乎在 RMSProp 中少了些什么. 原来是我们还没把 Momentum合并完全, RMSProp 还缺少了 momentum 中红色的这一部分. 所以, 我们在 Adam 方法中补上了这种想法.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xaL1r7s2-1610603071371)(attachment:image.png)]

(5)Adam 更新方法

计算m 时有 momentum 下坡的属性, 计算 v 时有 adagrad 阻力的属性, 然后再更新参数时 把 m 和 V 都考虑进去. 实验证明, 大多数时候, 使用 adam 都能又快又好的达到目标, 迅速收敛. 所以说, 在加速神经网络训练的时候, 一个下坡, 一双破鞋子, 功不可没.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9sWpvMI-1610603071372)(attachment:image.png)]

7 Optimizer 优化器

各种优化器对比:https://cs231n.github.io/neural-networks-3/
Pytorch中的优化器:https://pytorch.org/docs/stable/optim.html

为了对比上面说的几种优化器,这里先构造一组伪数据、创建神经网络,并为每一个优化器定义一个网络:

import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt

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,)

# 默认的 network 形式
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
        x = self.predict(x)             # linear output
        return x

# 为每个优化器创建一个 net
net_SGD         = Net()
net_Momentum    = Net()
net_RMSprop     = Net()
net_Adam        = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]

在这里插入图片描述

接下来在创建不同的优化器, 用来训练不同的网络. 并创建一个 loss_func 用来计算误差.

# different optimizers
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

接下来训练和 loss 画图.

    for epoch in range(EPOCH):
        # print('Epoch: ', epoch)
        for step, (b_x, b_y) in enumerate(loader):          # for each training step
            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(loc='best')
    plt.xlabel('Steps')
    plt.ylabel('Loss')
    plt.ylim((0, 0.2))
    plt.show()

在这里插入图片描述

总结:SGD 是最普通的优化器, 也可以说没有加速效果, 而 Momentum 是 SGD 的改良版, 它加入了动量原则. 后面的 RMSprop 又是 Momentum 的升级版. 而 Adam 又是 RMSprop 的升级版. 不过从这个结果中我们看到, Adam 的效果似乎比 RMSprop 要差一点. 所以说并不是越先进的优化器, 结果越佳. 我们在自己的试验中可以尝试不同的优化器, 找到那个最适合你数据/网络的优化器.

标签:plt,nn,self,torch,Pytorch,神经网络,mofanpy,net,data
来源: https://blog.csdn.net/qq_39330170/article/details/112605086

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有