莫烦 pytorch 建造第一个神经网络

莫烦主页:https://mofanpy.com/

3. 建造第一个神经网络

3.1 Regression 回归(关系拟合)

神经网络可以分成两种类型:分类(如房价问题)和回归(两类或多类)

import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

# 在torch当中,数据是有维度的
# torch.unsqueeze()把一维数据变成二维数据,torch只会处理二维数据
# [1,2,3,4]  一维数据
# [[1,2,3,4]]二维数据

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)

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

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

# 定义Neural Network
# 继承从torch来的模块Module
class Net(torch.nn.Module):
    # __init__搭建层所需要的信息
    def __init__(self, n_feature, n_hidden, n_output):
        # 搭图之前继承Net到这个模块
        super(Net, self).__init__()
        # 层命名为hidden
        self.hidden = torch.nn.Linear(n_feature, n_hidden) # 一层神经网络(隐藏层),输入数据的个数,输出神经元的个数
        # 预测的神经层
        self.predict = torch.nn.Linear(n_hidden, n_output)  # 预测y的值

    # forward神经网络前向传递的过程
    # 前面的层信息放到forward上面一个一个组合起来,在torch当中搭流程图
    def forward(self, x):
        x = F.relu(self.hidden(x))
        # self.hidden(x)输出n个hidden units,再用激活函数Rule激活
        x = self.predict(x)
        return x


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

# 可视化过程
plt.ion()
plt.show()

# 优化神经网络
# SGD 随机梯度下降
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
# lr 为学习率,一般小于1。
# 学习率是调节每一次梯度更新的步长,即神经网络优化一次的步幅,神经网络优化类似于寻找某个(Loss)函数的最小值
# 方法就是随机选个点,然后一点一点挪到最小值
# 如果学习率过大,可能你会离某个局部最小值越跳越远

# 计算误差的手段 MSELoss 均方差代价函数
loss_function = torch.nn.MSELoss()

# 开始训练,t为训练步数
for t in range(100):
    prediction = net(x)  # 预测值

    loss = loss_function(prediction, y)  # 计算预测值与真实值y两者误差

    optimizer.zero_grad()  # 把所有参数的梯度降为0
    loss.backward()  # 反向传递
    optimizer.step()  # 以学习效率0.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, fontdict={'size':20, 'color': 'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

3.2 Classification分类

import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

n_data = torch.ones(100, 2)     # data的基数
x0 = torch.normal(2*n_data, 1)      # class0 x data (tensor), shape=(100, 2)
# x0数据的标签是0(zeros)
y0 = torch.zeros(100)               # class0 y data (tensor), shape=(100, 1)
x1 = torch.normal(-2*n_data, 1)     # class1 x data (tensor), shape=(100, 1)
# x1数据的标签是1(ones)
y1 = torch.ones(100)                # class1 y data (tensor), shape=(100, 1)
# cat将x0和x1合并在一起当作数据
x = torch.cat((x0, x1), 0).type(torch.FloatTensor)  # FloatTensor = 32-bit floating
# 将y0和y1合并在一起当作标签
y = torch.cat((y0, y1), ).type(torch.LongTensor)    # LongTensor = 64-bit integer

# x, y = Variable(x), Variable(y)
# 新版本的tensor和Variable合并啦

# 可视化
# 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)
        self.predict = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x

net = Net(2, 10, 2)
# 输出结果为one-hot形式:使用N位状态寄存器来对N个状态进行编码
# 例如,在二分类中
# [0, 1] 为第二类
# [1, 0] 为第一类
# 在三分类中
# [0, 1, 0] 为第二类
print(net)

# 可视化过程
plt.ion()
plt.show()

optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
loss_function = torch.nn.CrossEntropyLoss()
# [0.2, 0.1, 0.7] = 1 预测值,概率总和为 1
# [0, 0, 1]标签值,CrossEntropyLoss计算标签值和预测值间的误差

for t in range(100):
    out = net(x)    # F.softmax(out)将输出的结果转换成概率值
    loss = loss_function(out, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if t % 2 == 0:
        # plot and show learning process
        plt.cla()
        prediction = torch.max(F.softmax(out), 1)[1]
        # torch.max()的返回值有两个,第一个是max值是多少,第二个是max的index,这里返回的是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, 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()

3.3 快速搭建法

# 定义神经网络的两种 methods
# method1
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)

    def forward(self, x):
        x = F.relu(self.hidden(x))    # relu是一个函数
        x = self.predict(x)
        return x

net1 = Net(2, 10, 2)

# method2 不用创建class
net2 = torch.nn.Sequential(    # 一层一层罗列神经层
    torch.nn.Linear(2, 10),
    torch.nn.ReLU(),    # ReLU是一个类
    torch.nn.Linear(10, 2)
)

print(net1)
print(net2)
输出结果:
Net(
  (hidden): Linear(in_features=2, out_features=10, bias=True)
  (predict): Linear(in_features=10, out_features=2, bias=True)
)
Sequential(
  (0): Linear(in_features=2, out_features=10, bias=True)
  (1): ReLU()
  (2): Linear(in_features=10, out_features=2, bias=True)
)

Process finished with exit code 0

3.4 保存提取

import torch
from torch.autograd import Variable
import matplotlib.pyplot as plt

torch.manual_seed(1)    # reproducible

# fake data
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.2)
    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()

    torch.save(net1, 'net.pkl')     # save entire net
    torch.save(net1.state_dict(), 'net_params.pkl')
    # save parameters,神经网络的状态,包括神经元的参数、dropout的参数
    # 速度快,占内存小


# 提取神经网络
def restore_net():
    net2 = torch.load('net.pkl')

def restore_params():
    # 首先建立一个跟net1一模一样的神经网络
    # 然后将net1的参数复制到net3中
    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'))

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

# 提取整个网络
restore_net()

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

3.5 批数据训练(minibatch training)

批训练可以提升速度,相对于单图训练而言的,因为全部数据过大,所以分批。

minibatch 集合了批梯度下降和随机梯度下降的优点。

import torch
import torch.utils.data as Data

# 5个为一组
BATCH_SIZE = 5

# 对于BATCH_SIZE不能整除数据量时,最后返回的是模数

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

# 定义一个数据库
# 旧版本为torch_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)
torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(
    dataset=torch_dataset,
    batch_size=BATCH_SIZE,
    shuffle=True, # shuffle 定义的是要不要在训练时随机打乱数据,然后再随机开始抽样
    # num_workers=2,    # 每一次loader提取出batch_x和batch_y的时候,用两个进程来提取的,效率更高
)

# epoch是整个训练集被训练算法遍历的次数
for epoch in range(3):
    for step, (batch_x, batch_y) in enumerate(loader):
        # batch_x, batch_y 是通过 enumerate 提取 x 和 y ,step 是每组(x, y)的序号
        # x 有10个数据,BATCH_SIZE 为5,即2个为一组,step 即为2
        # 相当于有 n 个训练样本,BATCH_SIZE 为 m,则每个 epoch 都要进行 n/m 个 step
        # training...
        print('Epoch: ', epoch, '| Step: ', '| batch_x: ',
              batch_x.numpy(), '| batch_y: ', batch_y.numpy())
注意:windows用户如果报RuntimeError,需要把num_workers=2注释掉
或者可以将epoch迭代写进函数main(),然后if__name__=='__main__':main();

3.6 加速神经网络训练(Speed Up Training)—— 优化器(Optimizer)

1. 准备工作

# prepare
import torch
import torch.utils.data as Data
import torch.nn.functional as F

# hyper parameters
LR = 0.01
BATCH_SIZE = 32
EPOCH = 12

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

torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True)

# 默认的神经网络框架
class Net(torch.nn.Module):
    def __init__(self,):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(1, 20)    # hidden layer 20个神经元的隐藏层
        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

2. 优化方法:大多方法是在更新神经网络参数那一步做改动

  • SGD(Stochastic Gradient Descent)随机梯度下降:醉汉回家的时候,摇摇晃晃地走了很多弯路。

W += -Learning rate * dx

# 利用默认神经网络框架建立神经网络,并用优化方法进行优化
net_SGD = Net()

# 建立优化器
opt_SGD =       torch.optim.SGD(net_SGD.parameters(), lr=LR)
  • Momentum:如果说 SGD 中梯度影响的是下降的方向的话,Momentum 中梯度影响的就是下降的速度。醉汉回家的路是下坡路,只要他往下走一点点,由于惯性原则 ,他就会不自觉地往下走,走的弯路也会变少。

m = b1 * m - Learning rate * dx

W += m

net_Momentum = Net()
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
# Momentum 和 SGD 就差了一个 b1*m,可以将 SGD 看作是 momentum(动量)=0 的Momentum
  • AdaGrad:在学习率上做改动,每一个参数的更新都会有它与众不同的学习效率,给醉酒的人一双不好走路的鞋子,使他摇晃着走路的脚疼,鞋子变成了走弯路的阻力,逼着他直着走。

v += dx^2

W += -Learning rate *dx/\sqrt{v}

  • RMSProp:把下坡和不好走的鞋子结合起来。Momentum ( 没有考虑Learningrate ) + AdaGrad

v = b1 * v + (1 - b1) * dx ^2

W += -Learning rate * dx/\sqrt{v}

net_RMSprop = Net()
opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
  • Adam:考虑了 Momentum 的 Learningrate

m = b1 * m + ( 1 - b1 ) * dx\rightarrow Momentum

v = b2 * v + ( 1 - b2 ) * dx^2\rightarrow AdaGrad

W += -Learning rate*m/\sqrt{v}

net_Adam = Net()
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))

3. 开始训练

loss_func = torch.nn.MSELoss()
losses_his = []   # record loss(history)

for epoch in range(EPOCH):
    print(epoch)
    for step, (batch_x, batch_y) in enumerate(loader):
        for net, opt, l_his in zip(nets, optimizers, losses_his):
            output = net(batch_x)   # get output for every net
            loss = loss_func(output, batch_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[0])      # loss recoder
            # 新版使用loss.item
            # tensor里只有一个数的时候可以用.item()直接提取
            l_his.append(loss.item())

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值