【Python学习】基于pytorch和pysimplegui实现中国人口预测算法部署


这里假设读者已经在Windows下安装好Anaconda并且已经初步学会使用conda命令和jupyter notebook。

1 环境与Package准备

读者可以参考我之前的博客【Python学习】纯终端命令开始你的Anaconda安装与Python环境管理当中的Python环境管理部分

1.1 创建Python3.6版本的环境

读者如果已经掌握了conda管理python环境,并且当前使用的python版本为python3,则可以跳过这部分。
(1) 在终端输入以下创建环境命令

conda create -n py36 python=3.6  #python=3.6指定python版本

输入"y",按回车键确认,如下图
在这里插入图片描述

1.2 激活Python3.6版本的环境

conda activate py36 # 这里py36是环境名

如下图,环境由默认的base切换到py36
在这里插入图片描述

1.3 安装用到的package

1.3.1 安装jupyter notebook、pytorch

安装jupyter notebook:

conda install jupyter

安装pytorch:

conda install pytorch torchvision cpuonly -c pytorch

在这里插入图片描述

1.3.2 安装pysimplegui、matplotlib

安装pysimplegui:

pip install pysimplegui

在这里插入图片描述
安装matplotlib:

pip install matplotlib

2 数据准备

数据来源:中国历年人口总数统计
选取1959年至2018年的中国人口数据作为训练样本

3 代码编写

打开jupyter notebook:

jupyter notebook

3.1 数据分析

创建jupyter notebook文件test_cpa.ipynb
在第1个cell导入相应包:

# 导入相应包
import torch
import numpy as np
import torch.nn.functional as F
import matplotlib.pyplot as plt
%matplotlib inline

在第2个cell绘图分析:

# 获取数据
year = torch.unsqueeze(torch.range(start=1959, end=2018, step=1, out=None), dim=1) 
year = year - 1958  # year-1958,假设1959年为第1年
cp = torch.unsqueeze(torch.tensor([6.55, 6.67, 6.6, 6.66, 6.82, 6.98, 7.15, 7.35, 7.55,
                                   7.75, 7.96, 8.18, 8.41, 8.62, 8.82, 9.0, 9.16, 9.31,
                                   9.43, 9.56, 9.69, 9.81, 9.94, 10.09, 10.23, 10.37, 10.51,
                                   10.67, 10.84, 11.02, 11.19, 11.35, 11.51, 11.65, 11.78, 11.92, 
                                   12.05, 12.18, 12.3, 12.42, 12.53, 12.63, 12.72, 12.8, 12.88,
                                   12.96, 13.04, 13.11, 13.18, 13.25, 13.31, 13.38, 13.44, 13.51,
                                   13.57, 13.64, 13.71, 13.79, 13.86, 13.93]), dim=1)   # 单位:亿
plt.scatter(year.data.numpy(), cp.data.numpy())
plt.show()

绘图结果如下:
在这里插入图片描述

3.2 模型搭建

这里主要使用感知机模型,感知机算法可以参考博客:李航《统计学习方法》第二章——用Python实现感知器模型(MNIST数据集)
创建cpa.py文件,在该文件中书写模型类:
该文件可以分为三步进行描述:

  • 第1步:导入相应包;
  • 第2步:书写PAnet类的构造函数__init__
  • 第3步,书写PAnet类的forward函数
#!/usr/bin/env python
# coding: utf-8

# # 中国人口分析
# **作者**:陈艺荣   
# **依赖**:python3.6、pytorch1.3.0    

# 导入相应包
import torch
import torch.nn.functional as F

class PAnet(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output, hidden_num=1):
        super(PAnet, self).__init__()
        self.hidden1 = torch.nn.Linear(n_feature, n_hidden)   # hidden1 layer
        self.hidden2 = torch.nn.ModuleList([torch.nn.Linear(n_hidden, n_hidden) for i in range(hidden_num)])
        self.predict = torch.nn.Linear(n_hidden, n_output)   # output layer        
        
    def forward(self, x):
        x = F.relu(self.hidden1(x)) 
        for i, h in enumerate(self.hidden2):
            x = F.relu(h(x))
        x = self.predict(x) # linear output
        return x

3.3 训练模型,调参

3.1 数据分析test_cpa.ipynb文件的基础上,建立第3个cell,设置随机种子,并且导入PAnet类

torch.manual_seed(1)    # reproducible
from cpa import PAnet

建立第4个cell,定义训练过程:

def train(EPOCH, LR, HIDDEN_SIZE, HIDDEN_LAYERS):
    '''
    EPOCH          训练次数
    LR             学习率
    HIDDEN_SIZE    隐藏层网络宽度
    HIDDEN_LAYERS  隐藏层深度
    
    '''
    time = np.arange(EPOCH)   # 产生自变量
    loss_list = []
    cn_panet = PAnet(n_feature=1, n_hidden=HIDDEN_SIZE, n_output=1, hidden_num=HIDDEN_LAYERS-1)     # define the network
    print(cn_panet)  # net architecture
    optimizer = torch.optim.SGD(cn_panet.parameters(), lr=LR)  # 调小学习率
    loss_func = torch.nn.MSELoss()  # this is for regression mean squared loss
    for t in range(EPOCH):
        prediction = cn_panet(year)          # input x and predict based on x
        loss = loss_func(prediction, cp)     # must be (1. nn output, 2. target)
        loss_list.append(loss)

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

建立第5个cell,对不同的学习率进行实验

# Hyper Parameters
EPOCH = 5000 # 训练次数
LR = 0.002 # 学习率
HIDDEN_SIZE = 30 # 隐藏层网络宽度
HIDDEN_LAYERS = 5 # 隐藏层深度
time, loss_list_02 = train(EPOCH, 0.2, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_0005 = train(EPOCH, 0.005, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_0002 = train(EPOCH, 0.002, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_0003 = train(EPOCH, 0.003, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_0004 = train(EPOCH, 0.004, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_0001 = train(EPOCH, 0.001, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_00002 = train(EPOCH, 0.0002, HIDDEN_SIZE, HIDDEN_LAYERS)
time, loss_list_000002 = train(EPOCH, 0.00002, HIDDEN_SIZE, HIDDEN_LAYERS)

建立第6个cell,对不同的学习率获得的结果进行绘图分析

plt.plot(time, loss_list_0001, 'g-', label='lr=0.001') 
plt.plot(time, loss_list_0002, 'b-', label='lr=0.002') 
plt.plot(time, loss_list_0003, 'k-', label='lr=0.003') 
plt.plot(time, loss_list_0004, 'y-', label='lr=0.004') 
plt.plot(time, loss_list_0005, 'r-', label='lr=0.005') 

plt.legend(loc='lower right')  # 说明图例  # loc='lower right' 设置图例放置位置

在这里插入图片描述

建立第7个cell,截取100个epoch之后的结果进行比较分析:

plt.plot(time[100:], loss_list_0001[100:], 'g-', label='lr=0.001') 
plt.plot(time[100:], loss_list_0002[100:], 'b-', label='lr=0.002') 
plt.plot(time[100:], loss_list_0003[100:], 'k-', label='lr=0.003') 
plt.plot(time[100:], loss_list_0004[100:], 'y-', label='lr=0.004') 
plt.plot(time[100:], loss_list_0005[100:], 'r-', label='lr=0.005') 
plt.legend(loc='lower right')  # 说明图例  # loc='lower right' 设置图例放置位置

在这里插入图片描述
这里依据上图对学习率进行简单分析:
可以看到,当学习率lr=0.005时,模型的loss下降到5就不再下降了;
当学习率lr=0.001时,模型的loss下降速度相对较慢;
当学习率lr=0.002或0.003时,模型的loss下降较快且接近0;

3.4 使用最优的参数训练模型并且保存

这里假设最优的超参数为:

  • EPOCH = 5000 # 训练次数
  • LR = 0.003 # 学习率
  • HIDDEN_SIZE = 32 # 隐藏层网络宽度
  • HIDDEN_LAYERS = 8 # 隐藏层深度
    新建jupyter notebook文件test_cpa_best_model.ipynb,在第1个cell导入包:
# 导入相应包
import torch
import numpy as np
import torch.nn.functional as F
import matplotlib.pyplot as plt
from cpa import PAnet
%matplotlib inline

建立第2个cell,放置训练数据

# 获取数据
year = torch.unsqueeze(torch.range(start=1959, end=2018, step=1, out=None), dim=1) 
year = year - 1958  # year-1958,假设1959年为第1年
cp = torch.unsqueeze(torch.tensor([6.55, 6.67, 6.6, 6.66, 6.82, 6.98, 7.15, 7.35, 7.55,
                                   7.75, 7.96, 8.18, 8.41, 8.62, 8.82, 9.0, 9.16, 9.31,
                                   9.43, 9.56, 9.69, 9.81, 9.94, 10.09, 10.23, 10.37, 10.51,
                                   10.67, 10.84, 11.02, 11.19, 11.35, 11.51, 11.65, 11.78, 11.92, 
                                   12.05, 12.18, 12.3, 12.42, 12.53, 12.63, 12.72, 12.8, 12.88,
                                   12.96, 13.04, 13.11, 13.18, 13.25, 13.31, 13.38, 13.44, 13.51,
                                   13.57, 13.64, 13.71, 13.79, 13.86, 13.93]), dim=1)   # 单位:亿
plt.scatter(year.data.numpy(), cp.data.numpy())
plt.show()

建立第3个cell,构建训练、保存模型函数:

# 训练并且保存网络函数
def trainandsave(EPOCH, LR, HIDDEN_SIZE, HIDDEN_LAYERS):
    '''
    EPOCH          训练次数
    LR             学习率
    HIDDEN_SIZE    隐藏层网络宽度
    HIDDEN_LAYERS  隐藏层深度
    
    '''
    time = np.arange(EPOCH)   # 产生自变量
    loss_list = []
    cn_panet = PAnet(n_feature=1, n_hidden=HIDDEN_SIZE, n_output=1, hidden_num=HIDDEN_LAYERS-1)     # define the network
    print(cn_panet)  # net architecture
    optimizer = torch.optim.SGD(cn_panet.parameters(), lr=LR)  # 调小学习率
    loss_func = torch.nn.MSELoss()  # this is for regression mean squared loss
    for t in range(EPOCH):
        prediction = cn_panet(year)          # input x and predict based on x
        loss = loss_func(prediction, cp)     # must be (1. nn output, 2. target)
        loss_list.append(loss)

        optimizer.zero_grad()                # clear gradients for next train
        loss.backward()                      # backpropagation, compute gradients
        optimizer.step()                     # apply gradients    
    torch.save(cn_panet, 'cn_panet.pkl')  # save entire net
    print("成功保存网络")
    return time, loss_list

建立第4个cell,定义读取模型函数:

# 读取网络模型函数
def restore_net(netname):
    # restore entire net1 to net2
    net = torch.load(netname)
    return net

建立第5个cell,使用最优参数训练模型:

# 根据最优参数进行配置
EPOCH = 5000 # 训练次数
LR = 0.003 # 学习率
HIDDEN_SIZE = 32 # 隐藏层网络宽度
HIDDEN_LAYERS = 8 # 隐藏层深度
time, loss_list_02 = trainandsave(EPOCH, LR, HIDDEN_SIZE, HIDDEN_LAYERS)
plt.plot(time, loss_list_02, 'g-', label='损失函数曲线') 

建立第6个cell,测试能否导入模型使用:

reload_net = restore_net('cn_panet.pkl')
year_2019 = 2019 - 1958
year_2019 = torch.FloatTensor([[year_2019]])
print(year_2019.shape)
cp_2019 = reload_net(year_2019)
print("预测的2019年人口为:",cp_2019.item(),"亿")

返回结果如下:
torch.Size([1, 1])
预测的2019年人口为: 14.121960639953613 亿

3.5 构建可视化界面部署模型,投入使用

新建jupyter notebook文件cpa_demo.ipynb,在第1个cell写入以下代码:

# 导入相应包
import torch
import numpy as np
import PySimpleGUI as sg
# 定义导入模型的函数
def restore_net(netname):
    # restore entire net1 to net2
    net = torch.load(netname)
    return net

# 窗口内的所有控件.
sg.change_look_and_feel('DarkBlue1')
layout = [ [sg.Text('选择你的数据模型')],
            [sg.Input(), sg.FileBrowse()],
            [sg.Text('输入需要预测的年份'), sg.InputText()],
            [sg.Button('确认'), sg.Button('退出')] ]
 
# 生成窗口
window = sg.Window('中国人口预测', layout)
# 消息处理和输入消息接收
while True:
    event, values = window.read()
    if event in (None, '退出'): 
        break
    reload_net = restore_net(values[0])
    year = torch.FloatTensor([[int(values[1])-1958]])
    predict_cp = reload_net(year)
    print(predict_cp)
    sg.Popup("预测的人口为:", predict_cp.item(),"亿")

window.close()
del window

运行后,弹出如下界面:
在这里插入图片描述
选择保存的模型,并且输入预测的年份,然后点击确认,结果如下:
在这里插入图片描述

4 总结

本文使用pytorch和pysimplegui实现中国人口数据分析,搭建多层感知机模型拟合数据,通过调参获得最优模型,并且把模型部署到界面应用当中。其中3.1节代码数据数据分析;3.2节代码数据模型搭建;3.3和3.4节代码属于网络调参;3.5节代码属于前端界面应用构建。通过本篇博客,你可以初步体验pytorch、numpy、matplotlib、pysimplegui的使用,以及python构建类的代码。
深度学习应用大致可以分为以下几步:

  • 数据准备与数据分析;
  • 模型搭建;
  • 模型超参数调参;
  • 训练模型并且保存;
  • 将训练好的模型部署到生产环境当中。

代码已经开源在:https://github.com/scutcyr/cpa_test

【作者简介】陈艺荣,男,目前在华南理工大学电子与信息学院广东省人体数据科学工程技术研究中心攻读博士,担任IEEE Access、IEEE Photonics Journal的审稿人。两次获得美国大学生数学建模竞赛(MCM)一等奖,获得2017年全国大学生数学建模竞赛(广东赛区)一等奖、2018年广东省大学生电子设计竞赛一等奖等科技竞赛奖项,主持一项2017-2019年国家级大学生创新训练项目获得优秀结题,参与两项广东大学生科技创新培育专项资金、一项2018-2019年国家级大学生创新训练项目获得良好结题,发表SCI论文3篇,授权实用新型专利8项,受理发明专利13项。
我的主页
我的Github
我的CSDN博客
我的Linkedin

  • 9
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

YirongChen

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值