【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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章