Pytorch_第四篇_使用pytorch快速搭建神经网络实现二分类任务(包含示例)

使用pytorch快速搭建神经网络实现二分类任务(包含示例)


Introduce

上一篇学习笔记介绍了不使用pytorch包装好的神经网络框架实现logistic回归模型,并且根据autograd实现了神经网络参数更新。

本文介绍利用pytorch快速搭建神经网络。即利用torch.nn以及torch.optim库来快捷搭建一个简单的神经网络来实现二分类功能。

  • 利用pytorch已经包装好的库(torch.nn)来快速搭建神经网络结构。
  • 利用已经包装好的包含各种优化算法的库(torch.optim)来优化神经网络中的参数,如权值参数w和阈值参数b。

以下均为初学者笔记,如有错误请不吝指出。


Build a neural network structure

假设我们要搭建一个带有两个隐层的神经网络来实现节点的二分类,输入层包括2个节点(输入节点特征),两个隐层均包含5个节点(特征映射),输出层包括2个节点(分别输出属于对应节点标签的概率)。如下图所示:


image

上图从左右到右为输入层、隐藏层、隐藏层、输出层,各层之间采用全连接结构。神经网络两隐藏层的激活函数均采用sigmoid函数,输出层最后采用softmax函数归一化概率。

网络搭建过程中使用的torch.nn相关模块介绍如下:

  • torch.nn.Sequential:是一个时序容器,我们可以通过调用其构造器,将神经网络模块按照输入层到输出层的顺序传入,以此构造完整的神经网络结构,具体用法参考如下神经网络搭建代码。
  • torch.nn.Linear:设置网络中的全连接层,用来实现网络中节点输入的线性求和,即实现如下线性变换函数:

y = xA^T + b


'''
搭建神经网络,
输入层包括2个节点,两个隐层均包含5个节点,输出层包括1个节点。'''

net = nn.Sequential(
    nn.Linear(2,5),  # 输入层与第一隐层结点数设置,全连接结构
    torch.nn.Sigmoid(),  # 第一隐层激活函数采用sigmoid
    nn.Linear(5,5),  # 第一隐层与第二隐层结点数设置,全连接结构
    torch.nn.Sigmoid(),  # 第一隐层激活函数采用sigmoid
    nn.Linear(5,2),  # 第二隐层与输出层层结点数设置,全连接结构
    nn.Softmax(dim=1) # 由于有两个概率输出,因此对其使用Softmax进行概率归一化,dim=1代表行归一化
)

 print(net)

'''
Sequential(
  (0): Linear(in_features=2, out_features=5, bias=True)
  (1): Sigmoid()
  (2): Linear(in_features=5, out_features=5, bias=True)
  (3): Sigmoid()
  (4): Linear(in_features=5, out_features=2, bias=True)
  (5): Softmax(dim=1)
)'''


Configure Loss Function and Optimizer

note: torch.optim库中封装了许多常用的优化方法,这边使用了最常用的随机梯度下降来优化网络参数。例子中使用了交叉熵损失作为代价函数,其实torch.nn中也封装了许多代价函数,具体可以查看官方文档。对于pytorch中各种损失函数的学习以及优化方法的学习将在后期进行补充。
配置损失函数和优化器的代码如下所示:

# 配置损失函数和优化器
optimizer = torch.optim.SGD(net.parameters(),lr=0.01) # 优化器使用随机梯度下降,传入网络参数和学习率
loss_func = torch.nn.CrossEntropyLoss() # 损失函数使用交叉熵损失函数

Model Training

神经网络训练过程大致如下:首先输入数据,接着神经网络进行前向传播,计算输出层的输出,进而计算预先定义好的损失(如本例中的交叉熵损失),接着进行误差反向传播,利用事先设置的优化方法(如本例中的随机梯度下降SGD)来更新网络中的参数,如权值参数w和阈值参数b。接着反复进行上述迭代,达到最大迭代次数(num_epoch)或者损失值满足某条件之后训练停止,从而我们可以得到一个由大量数据训练完成的神经网络模型。模型训练的代码如下所示:

# 模型训练
num_epoch = 10000 # 最大迭代更新次数
for epoch in range(num_epoch):
    y_p = net(x_t)  # 喂数据并前向传播

    loss = loss_func(y_p,y_t.long()) # 计算损失
    '''
    PyTorch默认会对梯度进行累加,因此为了不使得之前计算的梯度影响到当前计算,需要手动清除梯度。
    pyTorch这样子设置也有许多好处,但是由于个人能力,还没完全弄懂。
    '''
    optimizer.zero_grad()  # 清除梯度
    loss.backward()  # 计算梯度,误差回传
    optimizer.step()  # 根据计算的梯度,更新网络中的参数

    if epoch % 1000 == 0:
        print('epoch: {}, loss: {}'.format(epoch, loss.data.item()))
        
'''
每1000次输出损失如下:
epoch: 0, loss: 0.7303197979927063
epoch: 1000, loss: 0.669952392578125
epoch: 2000, loss: 0.6142827868461609
epoch: 3000, loss: 0.5110923051834106
epoch: 4000, loss: 0.4233965575695038
epoch: 5000, loss: 0.37978556752204895
epoch: 6000, loss: 0.3588798940181732
epoch: 7000, loss: 0.3476340174674988
                ......
'''

print("所有样本的预测标签: \n",torch.max(y_p,dim = 1)[1])

'''
note:可以发现前100个标签预测为0,后100个样本标签预测为1。因此所训练模型可以正确预测训练集标签。
所有样本的预测标签: 
 tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1])
'''


网络的保存和提取

'''两种保存方式
第一种: 保存网络的所有参数(包括网络结构)
    torch.save(net,'net.pkl')
对应加载方式: net1 = torch.load('net.pkl')
第二种: 仅保存网络中需要训练的参数 ,即net.state_dict(),如权值参数w和阈值参数b。(不包括网络结构)
    torch.save(net.state_dict(),'net_parameter.pkl')
对应加载方式: 
    加载时需要提供两个信息: 
    第一: 网络结构信息,需要先重新搭建和保存的网络同样的网络结构。
    第二: 保存的网络中的参数的信息,权值和阈值参数。
    具体加载方式如下:
    net = nn.Sequential(
    nn.Linear(2,5),  
    torch.nn.Sigmoid(),  
    nn.Linear(5,5),  
    torch.nn.Sigmoid(),  
    nn.Linear(5,2),  
    nn.Softmax(dim=1) 
    )
    net2.load_state_dict(torch.load('net_parameter.pkl')
    '''

本文参考-1

本文参考-2

附完整代码

import torch
import torch.nn as nn

'''
使用正态分布随机生成两类数据
第一类有100个点,使用均值为2,标准差为1的正态分布随机生成,标签为0。
第二类有100个点,使用均值为-2,标准差为1的正态分布随机生成,标签为1。
torch.normal(tensor1,tensor2)
输入两个张量,tensor1为正态分布的均值,tensor2为正态分布的标准差。
torch.normal以此抽取tensor1和tensor2中对应位置的元素值构造对应的正态分布以随机生成数据,返回数据张量。
'''

x1_t = torch.normal(2*torch.ones(100,2),1)
y1_t = torch.zeros(100)

x2_t = torch.normal(-2*torch.ones(100,2),1)
y2_t = torch.ones(100)

x_t = torch.cat((x1_t,x2_t),0)
y_t = torch.cat((y1_t,y2_t),0)

'''
搭建神经网络,
输入层包括2个节点,两个隐层均包含5个节点,输出层包括1个节点。
'''

net = nn.Sequential(
    nn.Linear(2,5),  # 输入层与第一隐层结点数设置,全连接结构
    torch.nn.Sigmoid(),  # 第一隐层激活函数采用sigmoid
    nn.Linear(5,5),  # 第一隐层与第二隐层结点数设置,全连接结构
    torch.nn.Sigmoid(),  # 第一隐层激活函数采用sigmoid
    nn.Linear(5,2),  # 第二隐层与输出层层结点数设置,全连接结构
    nn.Softmax(dim=1) # 由于有两个概率输出,因此对其使用Softmax进行概率归一化
)

print(net)
'''
Sequential(
  (0): Linear(in_features=2, out_features=5, bias=True)
  (1): Sigmoid()
  (2): Linear(in_features=5, out_features=5, bias=True)
  (3): Sigmoid()
  (4): Linear(in_features=5, out_features=2, bias=True)
  (5): Softmax(dim=1)
)'''

# 配置损失函数和优化器
optimizer = torch.optim.SGD(net.parameters(),lr=0.01) # 优化器使用随机梯度下降,传入网络参数和学习率
loss_func = torch.nn.CrossEntropyLoss() # 损失函数使用交叉熵损失函数

# 模型训练
num_epoch = 10000 # 最大迭代更新次数
for epoch in range(num_epoch):
    y_p = net(x_t)  # 喂数据并前向传播

    loss = loss_func(y_p,y_t.long()) # 计算损失
    '''
    PyTorch默认会对梯度进行累加,因此为了不使得之前计算的梯度影响到当前计算,需要手动清除梯度。
    pyTorch这样子设置也有许多好处,但是由于个人能力,还没完全弄懂。
    '''
    optimizer.zero_grad()  # 清除梯度
    loss.backward()  # 计算梯度,误差回传
    optimizer.step()  # 根据计算的梯度,更新网络中的参数

    if epoch % 1000 == 0:
        print('epoch: {}, loss: {}'.format(epoch, loss.data.item()))


'''
torch.max(y_p,dim = 1)[0]是每行最大的值
torch.max(y_p,dim = 1)[0]是每行最大的值的下标,可认为标签
'''
print("所有样本的预测标签: \n",torch.max(y_p,dim = 1)[1])


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354