首頁 > 易卦

基於Python TensorFlow Estimator DNNRegressor的深度學習程式碼

作者:由 瘋狂學習GIS 發表于 易卦日期:2023-01-17

列表框怎麼讀入文字

1 寫在前面

本文為基於TensorFlow

tf。estimator

介面的深度學習網路,而非TensorFlow 2。0中常用的

Keras

介面;關於

Keras

介面實現深度學習迴歸,

請看這裡

:https://blog。csdn。net/zhebushibiaoshifu/article/details/114016531。

本文程式碼以

DNNRegressor

迴歸為例;而由於基於

tf。estimator

介面的深度學習迴歸與分類整體較為類似,因此二者具有觸類旁通的效果。關於分類的一個具體例項,大家可以檢視

官網

:https://www。tensorflow。org/tutorials/estimator/premade。

本文第二部分為程式碼的分解介紹,第三部分為完整程式碼。

完整的。py格式程式碼可以在此

下載:

https://download。csdn。net/download/zhebushibiaoshifu/15447065。

相關版本資訊:

Python版本:3。8。5

TensorFlow版本:2。4。1

編譯器版本:Spyder 4。1。5

基於Python TensorFlow Estimator DNNRegressor的深度學習程式碼

基於Python TensorFlow Estimator DNNRegressor的深度學習程式碼

2 程式碼分解介紹

2。1 準備工作

首先需要引入相關的庫與包。

1

import

os

2

import

openpyxl

3

import

numpy

as

np

4

import

pandas

as

pd

5

import

tensorflow

as

tf

6

import

scipy。stats

as

stats

7

import

matplotlib。pyplot

as

plt

8

from

sklearn

import

metrics

9

from

sklearn。model_selection

import

train_test_split

其次,基於TensorFlow的程式碼往往會輸出較多的日誌資訊,從而使得我們對程式碼執行情況的瞭解受到一定影響。程式碼輸出的日誌資訊有四種,依據嚴重程度由低到高排序:INFO(通知)

1

os。environ[

‘TF_CPP_MIN_LOG_LEVEL’

]=

‘3’

來對TensorFlow的輸出日誌資訊加以約束。其中,“3”代表只輸出FATAL資訊。但要注意,這句程式碼需要放在 import tensorflow的前面:

1

import

os

2

os。environ[

‘TF_CPP_MIN_LOG_LEVEL’

]=

‘3’

3

import

openpyxl

4

import

numpy

as

np

5

import

pandas

as

pd

6

import

tensorflow

as

tf

7

import

scipy。stats

as

stats

8

import

matplotlib。pyplot

as

plt

9

from

sklearn

import

metrics

10

from

sklearn。model_selection

import

train_test_split

2。2 引數配置

深度學習程式碼一大特點即為具有較多的引數需要我們手動定義。為避免調參時上下翻找,我們可以將主要的引數集中在一起,方便我們後期調整。

其中,具體引數的含義在本文後續部分詳細介紹。

1

# 將各類變數放在一個位置集中定義,十分有利於機器學習等變數較多的程式碼

2

MyModelPath=

“G:/CropYield/03_DL/02_DNNModle”

# 確定每一次訓練所得模型儲存的位置

3

MyDataPath=

“G:/CropYield/03_DL/00_Data/AllDataAll。csv”

# 確定輸入資料的位置

4

MyResultSavePath=

“G:/CropYield/03_DL/03_OtherResult/EvalResult54。xlsx”

# 確定模型精度結果(RMSE等)與模型引數儲存的位置

5

TestSize=

0。2

# 確定資料中測試集所佔比例

6

RandomSeed=np。random。randint(low=

24

,high=

25

# 確定劃分訓練集與測試集的隨機數種子

7

OptMethod=

‘Adam’

# 確定模型所用的最佳化方法

8

LearningRate=

0。01

# 確定學習率

9

DecayStep=

200

# 確定學習率下降的步數

10

DecayRate=

0。96

# 確定學習率下降比率

11

HiddenLayer=[

64

128

# 確定隱藏層數量與每一層對應的神經元數量

12

ActFun=

‘tf。nn。relu’

# 確定啟用函式

13

Dropout=

0。3

# 確定Dropout的值

14

LossReduction=

‘tf。compat。v1。ReductionV2。SUM_OVER_BATCH_SIZE’

# 指定每個批次訓練誤差的減小方法

15

BatchNorm=

‘False’

# 確定是否使用Batch Normalizing

16

TrainBatchSize=

110

# 確定訓練資料一個Batch的大小

17

TrainStep=

3000

# 確定訓練資料的Step數量

18

EvalBatchSize=

1

# 確定驗證資料一個Batch的大小

19

PredictBatchSize=

1

# 確定預測資料(即測試集)一個Batch的大小

2。3 原有模型刪除

DNNRegressor

每執行一次,便會在指定路徑中儲存當前執行的模型。為保證下一次模型儲存時不受上一次模型執行結果乾擾,我們可以將模型資料夾內的全部檔案刪除。

1

# DeleteOldModel函式,刪除上一次執行所儲存的模型

2

def

DeleteOldModel

(ModelPath)

3

AllFileName=os。listdir(ModelPath)

# 獲取ModelPath路徑下全部檔案與資料夾

4

for

i

in

AllFileName:

5

NewPath=os。path。join(ModelPath,i)

# 分別將所獲取的檔案或資料夾名稱與ModelPath路徑組合

6

if

os。path。isdir(NewPath):

# 若組合後的新路徑是一個資料夾

7

DeleteOldModel(NewPath)

# 遞迴呼叫DeleteOldModel函式

8

else

9

os。remove(NewPath)

# 若不是一個新的資料夾,而是一個檔案,那麼就刪除

10

11

# 呼叫DeleteOldModel函式,刪除上一次執行所儲存的模型

12

DeleteOldModel(MyModelPath)

需要注意,以上程式碼僅刪除指定路徑下的檔案,資料夾不刪除。大家如果需要將資料夾也同時刪除,修改以上程式碼函式中的後面幾句即可。

2。4 資料匯入與資料劃分

我的資料已經儲存在了csv檔案中,因此可以用

pd。read_csv

直接讀取。

其中,資料的每一列是一個特徵,每一行是全部特徵與因變數(就是下面的Yield)組合成的樣本。

1

# LoadData函式,載入全部資料

2

def

LoadData

(DataPath)

3

MyData=pd。read_csv(DataPath,names=[

‘EVI0610’

‘EVI0626’

‘EVI0712’

‘EVI0728’

‘EVI0813’

‘EVI0829’

4

‘EVI0914’

‘EVI0930’

‘EVI1016’

‘Lrad06’

‘Lrad07’

‘Lrad08’

5

‘Lrad09’

‘Lrad10’

‘Prec06’

‘Prec07’

‘Prec08’

‘Prec09’

6

‘Prec10’

‘Pres06’

‘Pres07’

‘Pres08’

‘Pres09’

‘Pres10’

7

‘SIF161’

‘SIF177’

‘SIF193’

‘SIF209’

‘SIF225’

‘SIF241’

8

‘SIF257’

‘SIF273’

‘SIF289’

‘Shum06’

‘Shum07’

‘Shum08’

9

‘Shum09’

‘Shum10’

‘SoilType’

‘Srad06’

‘Srad07’

‘Srad08’

10

‘Srad09’

‘Srad10’

‘Temp06’

‘Temp07’

‘Temp08’

‘Temp09’

11

‘Temp10’

‘Wind06’

‘Wind07’

‘Wind08’

‘Wind09’

‘Wind10’

12

‘Yield’

],header=

0

# 載入DataPath路徑所指定的資料,names中的內容為各列的名稱

13

return

MyData

14

15

# 初始資料處理

16

AllXY=LoadData(MyDataPath)

# 呼叫LoadData函式,獲取資料

17

Label={

“Yield”

:AllXY。pop(

“Yield”

)}

# 將因變數從全部資料中提取出

18

AllX,AllY=AllXY,(pd。DataFrame(Label))

# 將自變數與因變數分離

19

20

# 劃分資料訓練集與測試集

21

TrainX,TestX,TrainY,TestY=train_test_split(AllX,

22

AllY,

23

test_size=TestSize,

# 指定資料中測試集所佔比例

24

random_state=RandomSeed

# 指定劃分訓練集與測試集的隨機數種子

25

2。5 Feature Columns定義

Feature Columns就是一個橋樑,聯絡你的初始資料與模型;其好比一個名單,模型拿著這個名單到你的資料(即2。4部分你匯入的資料)中按列的名稱一一搜索,若初始資料中的某列名稱在Feature Columns裡,那麼模型就會把初始資料中這一列的資料全部拿到自己這裡,進行訓練。

因為我們是希望匯入資料的全部特徵,那麼可以直接在全部資料的自變數中迴圈,將全部特徵的名稱匯入Feature Columns。

在這裡需要注意的是,只有連續數值變數才可以用

tf。feature_column。numeric_column

處理;若是類別變數可以參考:https://blog。csdn。net/zhebushibiaoshifu/article/details/115335441。

1

# estimator介面中的模型需要用“Feature columns”物件作為輸入資料,只有這樣模型才知道讀取哪些資料

2

FeatureColumn=[]

# 定義一個新的“Feature columns”物件

3

for

key

in

AllX。keys():

4

FeatureColumn。append(tf。feature_column。numeric_column(key=key))

# 將全部因變數資料(需要均為連續變數)匯入

2。6 模型最佳化方法構建與模型結構構建

模型最佳化方法即模型中的

optimizer

,其可以在模型結構構建時輸入;但有時最佳化方法較為複雜(例如引入了學習率下降),那麼在構建模型時配置最佳化方法的話就會有些不方便。因此我們首先構建模型最佳化方法。

1

# 定義模型最佳化方法

2

# Optimizer=OptMethod # 最佳化方法選用OptMethod所指定的方法

3

Optimizer=

lambda

:tf。keras。optimizers。Adam(

4

learning_rate=tf。compat。v1。train。exponential_decay(learning_rate=LearningRate,

# 初始學習率

5

global_step=tf。compat。v1。train。get_global_step(),

6

# 全域性步數,用以計算已經衰減後的學習率

7

# get_global_step()函式自動獲取當前的已經執行的步數

8

decay_steps=DecayStep,

# 學習率下降完成的指定步數

9

decay_rate=DecayRate

# 衰減率

10

# 選用基於學習率指數下降的Adam方法,此舉有助於降低過擬合風險

11

# 這一函式返回每次對應的學習率

12

以上程式碼中有兩個

Optimizer=

,第一個是直接輸入最佳化方法的名稱即可,名稱包括:‘Adagrad’, ‘Adam’, ‘Ftrl’, ‘RMSProp’, SGD‘;預設為Adagrad。

第二個是在選擇了最佳化方法的基礎上,配置其他資訊。例如第二個,其代表著學習率指數下降的Adam最佳化方法。其中,

tf。compat。v1。train。exponential_decay

可視作一個計算每次訓練學習率的函式,他返回的是每一次對應的學習率。可能這麼說不太好理解,看這個公式:其返回值為

learning_rate *decay_rate ^ (global_step / decay_steps)

,是不是就明白啦。

我們選擇第二個最佳化方法,因此把第一個註釋掉。

隨後,我們定義模型的結構。

1

# 基於DNNRegressor構建深度學習模型

2

DNNModel=tf。estimator。DNNRegressor(feature_columns=FeatureColumn,

# 指定模型所用的“Feature columns”物件

3

hidden_units=HiddenLayer,

# 指定隱藏層數量與每一層對應的神經元數量

4

optimizer=Optimizer,

# 指定模型所用的最佳化方法

5

activation_fn=eval(ActFun),

# 指定啟用函式

6

dropout=Dropout,

# 指定Dropout的值

7

label_dimension=

1

# 輸出資料的維度,即因變數的個數

8

model_dir=MyModelPath,

# 指定每一次訓練所得模型儲存的位置

9

# loss_reduction=eval(LossReduction), # 指定每個批次訓練誤差的減小方法

10

batch_norm=eval(BatchNorm)

# 指定是否使用Batch Normalizing

11

模型的構建,對照著程式碼上的註釋,就比較好理解了;其中,我把

loss_reduction

註釋掉,是因為可能由於TensorFlow版本的問題,其總是報錯,所以就用預設的值就好;而最後一個

batch_norm

,決定了是否進行Batch Normalizing。Batch Normalizing可以保持深度神經網路在每一層保持相同分佈,從而加快網路收斂與增強網路穩固性。

其它引數可以參考:https://www。tensorflow。org/api_docs/python/tf/estimator/DNNRegressor,或參考:https://www。tensorflow。org/api_docs/python/tf/nn

2。7 模型訓練

訓練模型這一部分,我認為反而比模型的構建可能還難理解一些。我們先看程式碼:

1

# 基於訓練資料訓練模型

2

DNNModel。train(input_fn=

lambda

:InputFun(TrainX,

3

TrainY,

4

True

5

TrainBatchSize

6

),

# 呼叫InputFun函式;InputFun函式返回“tf。data。Dataset”物件,這個物件才可以被

7

# train函式識別並帶入模型;由於InputFun函式每次返回BatchSize大小的資料個數,

8

# 因此需要多次執行,前面需要加lambda

9

steps=TrainStep

# 指定模型訓練的步數

10

我們可以這麼理解:在

train

函式中,只有一個引數

input_fn

;而這個引數的輸入,又是一個新的函式——這個新的函式就是大名鼎鼎的

input function

了。

他長這個樣子:

1

# InputFun函式,訓練資料與驗證資料所用的Input函式

2

def

InputFun

(Features,Labels,Training,BatchSize)

3

Datasets=tf。data。Dataset。from_tensor_slices((dict(Features),Labels))

# 對資料加以載入

4

if

Training:

5

Datasets=Datasets。shuffle(

1000

)。repeat()

# 對於訓練資料,需要打亂(shuffle)、重複(repeat)

6

return

Datasets。batch(BatchSize)

# 將經過上述處理後的資料以每次BatchSize個輸出

那我們首先就看

input function

——也就是程式碼中的

InputFun

函式。其實這個函式的用處很簡單,用官網的話說,其就是用來輸入模型支援的資料型別的——只有經過

input function

處理後,資料才可以被

DNNRegressor

識別。聽上去這麼厲害,它到底是如何操作的呢?

很簡單,它只需要將初始的資料轉換為特定的格式即可,這個格式是一個元組(tuple),這個元組有兩個元素:

一就是

features

,是一個字典。這個字典的每一個鍵是每一個特徵的名稱,就比如用植物特性對花的種類加以區分,那麼花的“葉長”“葉片厚度”等等就是一個個特徵的名稱,也就是這裡的一個個“鍵”;而這個字典的值,就是這個特徵對應的全部樣本的數值組成的陣列。

二就是

label

,是全部樣本對應的label,也就是因變數。

不知道大家有沒有理解,我們就舉一個簡單的例子。假如我們用兩個地方的溫度與降水預測這兩個地方的作物產量:其溫度分別為10 ℃、20 ℃,降水分別為15 mm,25 mm,作物產量分別為100千克每公頃,150千克每公頃——那麼tuple由兩個部分組成:

1

tuple=(features,label)

2

features={

’溫度‘

:np。array([

10

20

]),

’降水‘

:np。array([

15

25

])}

3

label=np。array([

100

150

])

怎麼樣,是不是明白啦。

理解了之後,我們繼續看

InputFun

函式。首先,

tf。data。Dataset。from_tensor_slices

用來將輸入的資料載入並轉換為Datase的形式;隨後,如果是訓練狀態下,那麼資料會進行打亂

。shuffle(1000)

——相當於對資料加以洗牌,防止初始資料具有一定的趨勢。例如如果我們做分類,其中初始資料的前80%都是第一類,後20%都是第二類,那麼如果我們不打亂資料,會使得用前80%資料訓練出來的結果都是第一類(即模型只認識第一類),在後20%進行測試時,所得結果也全都為第一類;所以要打亂。其中的1000是

buffer_size

引數,這個資料必須要比你的資料樣本個數大。至於

。shuffle(1000)

這個函式的原理我一直沒有搞明白,大家感興趣的話可以瞭解一下:https://www。tensorflow。org/api_docs/python/tf/data/Dataset#shuffle。

。repeat()

則是對資料集加以重複,之所以要重複,是因為我們需要對全部資料訓練好幾輪(即好幾個

Epoch

),因此要對初始資料加以重複。

隨後,用

。batch()

函式輸出BatchSize個數據,也就是一批資料;其中BatchSize就是每一批資料的個數。

這個就是

InputFun

函式。再看

train

函式函式:大家也看出來了,這個

InputFun

函式是每次輸出一批(BatchSize個)資料;而我們訓練的時候,肯定是要一批一批不停輸入資料的,因此這就解釋了為什麼

InputFun

函式前有一個

lambda

——因為

InputFun

函式要把處理後的資料分多次傳給

train

2。8 模型驗證與測試

理解了以上內容,接下來就好理解多了。我們需要進行驗證與測試的操作——其實驗證也就是利用了測試集資料,之所以我還進行了測試,是因為希望可以獲取測試集預測結果,從而更直觀地瞭解模型精度水平。

1

# InputFunPredict函式,測試資料所用的Input函式

2

def

InputFunPredict

(Features,BatchSize)

3

return

tf。data。Dataset。from_tensor_slices(dict(Features))。batch(BatchSize)

# 對資料加以載入,以每次BatchSize個輸出

4

5

# 驗證模型並儲存驗證結果

6

EvalResult=DNNModel。evaluate(input_fn=

lambda

:InputFun(TestX,

7

TestY,

8

False

9

EvalBatchSize

10

11

12

# 列印驗證結果

13

print(

’ev:{}‘

。format(EvalResult))

14

15

# 基於測試資料測試模型精度結果

16

PredictValues=DNNModel。predict(input_fn=

lambda

:InputFunPredict(TestX,

17

PredictBatchSize

18

19

其中,驗證時

。evaluate

所用的

InputFun

函式其實和訓練集所用的是一樣的函式,只不過驗證時不需要進行打亂

。shuffle(1000)

和重複

。repeat()

操作;而測試時

。predict

InputFun

函式則是新的,其只需要輸入自變數、無需輸入因變數。

2。9 精度評定、擬合影象繪製與模型引數與精度結果儲存

精度評定與擬合影象就不用過多說啦~最終,我們最好將模型引數與精度衡量指標結果儲存在Excel表格中,這樣子方便之後的調參過程。這裡就不再一一介紹啦,大家對照程式碼中的註釋即可。

1

# AccuracyVerification函式,進行精度驗證指標的計算與繪圖

2

def

AccuracyVerification

(PredictLabels,TestLabels)

3

value=

0

4

PredictValuesList=[]

5

for

k

in

PredictLabels:

6

value=k。get(

’predictions‘

)[

0

7

PredictValuesList。append(value)

8

TestLabels=TestLabels。values。tolist()

9

TestYList=sum(TestLabels,[])

10

# 以上為獲取測試資料的因變數與模型預測所得的因變數

11

Pearsonr=stats。pearsonr(TestYList,PredictValuesList)

# 計算皮爾遜相關係數

12

R2=metrics。r2_score(TestYList,PredictValuesList)

# 計算R方

13

RMSE=metrics。mean_squared_error(TestYList,PredictValuesList)**

0。5

# 計算RMSE

14

plt。cla()

15

plt。plot(TestYList,PredictValuesList,

’r*‘

16

plt。xlabel(

’Actual Values‘

17

plt。ylabel(

’Predicted Values‘

18

# 以上為繪製擬合影象

19

print(

’Pearson correlation coefficient is {0}, and RMSE is {1}。‘

。format(Pearsonr[

0

],RMSE))

20

return

(Pearsonr[

0

],R2,RMSE,PredictValuesList)

21

22

# WriteAccuracy函式,將模型所涉及的引數與最終精度結果儲存

23

def

WriteAccuracy

(*WriteVar)

24

ExcelData=openpyxl。load_workbook(WriteVar[

0

])

25

SheetName=ExcelData。get_sheet_names()

# 獲取全部Sheet

26

WriteSheet=ExcelData。get_sheet_by_name(SheetName[

0

])

# 獲取指定Sheet

27

WriteSheet=ExcelData。active

# 啟用指定Sheet

28

MaxRowNum=WriteSheet。max_row

# 獲取指定Sheet對應第一個空行

29

for

i

in

range(len(WriteVar)

-1

):

30

exec(

“WriteSheet。cell(MaxRowNum+1,i+1)。value=WriteVar[i+1]”

# 用exec執行語句,寫入資訊

31

ExcelData。save(WriteVar[

0

])

# 儲存檔案

32

33

# 呼叫AccuracyVerification函式,進行精度驗證指標的計算與繪圖

34

AccuracyResult=AccuracyVerification(PredictValues,TestY)

35

PearsonR,R2,RMSE,PredictY=AccuracyResult[

0

],AccuracyResult[

1

],AccuracyResult[

2

],AccuracyResult[

3

36

37

# 呼叫WriteAccuracy函式,將模型所涉及的引數與最終精度結果儲存

38

WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,

39

DecayRate,

’,‘

。join(

’%s‘

%i

for

i

in

HiddenLayer),ActFun,Dropout,LossReduction,

40

BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

至此,全部的程式碼分解介紹都結束啦~

3 詳細程式碼

1

# -*- coding: utf-8 -*-

2

“”“

3

Created on Tue Feb 23 16:13:21 2021

4

5

@author: Chutj

6

”“”

7

8

# 載入必要的庫、包等

9

import

os

10

os。environ[

’TF_CPP_MIN_LOG_LEVEL‘

]=

’3‘

11

import

openpyxl

12

import

numpy

as

np

13

import

pandas

as

pd

14

import

tensorflow

as

tf

15

import

scipy。stats

as

stats

16

import

matplotlib。pyplot

as

plt

17

from

sklearn

import

metrics

18

from

sklearn。model_selection

import

train_test_split

19

20

# ===============*** 函式宣告區域 ***===============

21

22

# DeleteOldModel函式,刪除上一次執行所儲存的模型

23

def

DeleteOldModel

(ModelPath)

24

AllFileName=os。listdir(ModelPath)

# 獲取ModelPath路徑下全部檔案與資料夾

25

for

i

in

AllFileName:

26

NewPath=os。path。join(ModelPath,i)

# 分別將所獲取的檔案或資料夾名稱與ModelPath路徑組合

27

if

os。path。isdir(NewPath):

# 若組合後的新路徑是一個資料夾

28

DeleteOldModel(NewPath)

# 遞迴呼叫DeleteOldModel函式

29

else

30

os。remove(NewPath)

# 若不是一個新的資料夾,而是一個檔案,那麼就刪除

31

32

# LoadData函式,載入全部資料

33

def

LoadData

(DataPath)

34

MyData=pd。read_csv(DataPath,names=[

’EVI0610‘

’EVI0626‘

’EVI0712‘

’EVI0728‘

’EVI0813‘

’EVI0829‘

35

’EVI0914‘

’EVI0930‘

’EVI1016‘

’Lrad06‘

’Lrad07‘

’Lrad08‘

36

’Lrad09‘

’Lrad10‘

’Prec06‘

’Prec07‘

’Prec08‘

’Prec09‘

37

’Prec10‘

’Pres06‘

’Pres07‘

’Pres08‘

’Pres09‘

’Pres10‘

38

’SIF161‘

’SIF177‘

’SIF193‘

’SIF209‘

’SIF225‘

’SIF241‘

39

’SIF257‘

’SIF273‘

’SIF289‘

’Shum06‘

’Shum07‘

’Shum08‘

40

’Shum09‘

’Shum10‘

’SoilType‘

’Srad06‘

’Srad07‘

’Srad08‘

41

’Srad09‘

’Srad10‘

’Temp06‘

’Temp07‘

’Temp08‘

’Temp09‘

42

’Temp10‘

’Wind06‘

’Wind07‘

’Wind08‘

’Wind09‘

’Wind10‘

43

’Yield‘

],header=

0

# 載入DataPath路徑所指定的資料,names中的內容為各列的名稱

44

return

MyData

45

46

# InputFun函式,訓練資料與驗證資料所用的Input函式

47

def

InputFun

(Features,Labels,Training,BatchSize)

48

Datasets=tf。data。Dataset。from_tensor_slices((dict(Features),Labels))

# 對資料加以載入

49

if

Training:

50

Datasets=Datasets。shuffle(

1000

)。repeat()

# 對於訓練資料,需要打亂(shuffle)、重複(repeat)

51

return

Datasets。batch(BatchSize)

# 將經過上述處理後的資料以每次BatchSize個輸出

52

53

# InputFunPredict函式,測試資料所用的Input函式

54

def

InputFunPredict

(Features,BatchSize)

55

return

tf。data。Dataset。from_tensor_slices(dict(Features))。batch(BatchSize)

# 對資料加以載入,以每次BatchSize個輸出

56

57

# AccuracyVerification函式,進行精度驗證指標的計算與繪圖

58

def

AccuracyVerification

(PredictLabels,TestLabels)

59

value=

0

60

PredictValuesList=[]

61

for

k

in

PredictLabels:

62

value=k。get(

’predictions‘

)[

0

63

PredictValuesList。append(value)

64

TestLabels=TestLabels。values。tolist()

65

TestYList=sum(TestLabels,[])

66

# 以上為獲取測試資料的因變數與模型預測所得的因變數

67

Pearsonr=stats。pearsonr(TestYList,PredictValuesList)

# 計算皮爾遜相關係數

68

R2=metrics。r2_score(TestYList,PredictValuesList)

# 計算R方

69

RMSE=metrics。mean_squared_error(TestYList,PredictValuesList)**

0。5

# 計算RMSE

70

plt。cla()

71

plt。plot(TestYList,PredictValuesList,

’r*‘

72

plt。xlabel(

’Actual Values‘

73

plt。ylabel(

’Predicted Values‘

74

# 以上為繪製擬合影象

75

print(

’Pearson correlation coefficient is {0}, and RMSE is {1}。‘

。format(Pearsonr[

0

],RMSE))

76

return

(Pearsonr[

0

],R2,RMSE,PredictValuesList)

77

78

# WriteAccuracy函式,將模型所涉及的引數與最終精度結果儲存

79

def

WriteAccuracy

(*WriteVar)

80

ExcelData=openpyxl。load_workbook(WriteVar[

0

])

81

SheetName=ExcelData。get_sheet_names()

# 獲取全部Sheet

82

WriteSheet=ExcelData。get_sheet_by_name(SheetName[

0

])

# 獲取指定Sheet

83

WriteSheet=ExcelData。active

# 啟用指定Sheet

84

MaxRowNum=WriteSheet。max_row

# 獲取指定Sheet對應第一個空行

85

for

i

in

range(len(WriteVar)

-1

):

86

exec(

“WriteSheet。cell(MaxRowNum+1,i+1)。value=WriteVar[i+1]”

# 用exec執行語句,寫入資訊

87

ExcelData。save(WriteVar[

0

])

# 儲存檔案

88

89

90

# ===============*** 程式碼由此開始執行 ***===============

91

# ++++++++++——- 建議由這裡開始看 ——-++++++++++

92

93

# 將各類變數放在一個位置集中定義,十分有利於機器學習等變數較多的程式碼

94

MyModelPath=

“G:/CropYield/03_DL/02_DNNModle”

# 確定每一次訓練所得模型儲存的位置

95

MyDataPath=

“G:/CropYield/03_DL/00_Data/AllDataAll。csv”

# 確定輸入資料的位置

96

MyResultSavePath=

“G:/CropYield/03_DL/03_OtherResult/EvalResult54。xlsx”

# 確定模型精度結果(RMSE等)與模型引數儲存的位置

97

TestSize=

0。2

# 確定資料中測試集所佔比例

98

RandomSeed=np。random。randint(low=

24

,high=

25

# 確定劃分訓練集與測試集的隨機數種子

99

OptMethod=

’Adam‘

# 確定模型所用的最佳化方法

100

LearningRate=

0。01

# 確定學習率

101

DecayStep=

200

# 確定學習率下降的步數

102

DecayRate=

0。96

# 確定學習率下降比率

103

HiddenLayer=[

64

128

# 確定隱藏層數量與每一層對應的神經元數量

104

ActFun=

’tf。nn。relu‘

# 確定啟用函式

105

Dropout=

0。3

# 確定Dropout的值

106

LossReduction=

’tf。compat。v1。ReductionV2。SUM_OVER_BATCH_SIZE‘

# 指定每個批次訓練誤差的減小方法

107

BatchNorm=

’False‘

# 確定是否使用Batch Normalizing

108

TrainBatchSize=

110

# 確定訓練資料一個Batch的大小

109

TrainStep=

3000

# 確定訓練資料的Step數量

110

EvalBatchSize=

1

# 確定驗證資料一個Batch的大小

111

PredictBatchSize=

1

# 確定預測資料(即測試集)一個Batch的大小

112

113

# 呼叫DeleteOldModel函式,刪除上一次執行所儲存的模型

114

DeleteOldModel(MyModelPath)

115

116

# 初始資料處理

117

AllXY=LoadData(MyDataPath)

# 呼叫LoadData函式,獲取資料

118

Label={

“Yield”

:AllXY。pop(

“Yield”

)}

# 將因變數從全部資料中提取出

119

AllX,AllY=AllXY,(pd。DataFrame(Label))

# 將自變數與因變數分離

120

121

# 劃分資料訓練集與測試集

122

TrainX,TestX,TrainY,TestY=train_test_split(AllX,

123

AllY,

124

test_size=TestSize,

# 指定資料中測試集所佔比例

125

random_state=RandomSeed

# 指定劃分訓練集與測試集的隨機數種子

126

127

128

# estimator介面中的模型需要用“Feature columns”物件作為輸入資料,只有這樣模型才知道讀取哪些資料

129

FeatureColumn=[]

# 定義一個新的“Feature columns”物件

130

for

key

in

AllX。keys():

131

FeatureColumn。append(tf。feature_column。numeric_column(key=key))

# 將全部因變數資料(需要均為連續變數)匯入

132

133

# 定義模型最佳化方法

134

# Optimizer=OptMethod # 最佳化方法選用OptMethod所指定的方法

135

Optimizer=

lambda

:tf。keras。optimizers。Adam(

136

learning_rate=tf。compat。v1。train。exponential_decay(learning_rate=LearningRate,

# 初始學習率

137

global_step=tf。compat。v1。train。get_global_step(),

138

# 全域性步數,用以計算已經衰減後的學習率

139

# get_global_step()函式自動獲取當前的已經執行的步數

140

decay_steps=DecayStep,

# 學習率下降完成的指定步數

141

decay_rate=DecayRate

# 衰減率

142

# 選用基於學習率指數下降的Adam方法,此舉有助於降低過擬合風險

143

# 這一函式返回每次對應的學習率

144

145

146

147

# 基於DNNRegressor構建深度學習模型

148

DNNModel=tf。estimator。DNNRegressor(feature_columns=FeatureColumn,

# 指定模型所用的“Feature columns”物件

149

hidden_units=HiddenLayer,

# 指定隱藏層數量與每一層對應的神經元數量

150

optimizer=Optimizer,

# 指定模型所用的最佳化方法

151

activation_fn=eval(ActFun),

# 指定啟用函式

152

dropout=Dropout,

# 指定Dropout的值

153

label_dimension=

1

# 輸出資料的維度,即因變數的個數

154

model_dir=MyModelPath,

# 指定每一次訓練所得模型儲存的位置

155

# loss_reduction=eval(LossReduction), # 指定每個批次訓練誤差的減小方法

156

batch_norm=eval(BatchNorm)

# 指定是否使用Batch Normalizing

157

158

159

# tf。compat。v1。logging。set_verbosity(tf。compat。v1。logging。INFO) # 將INFO級別的日誌資訊顯示到螢幕

160

161

# 基於訓練資料訓練模型

162

DNNModel。train(input_fn=

lambda

:InputFun(TrainX,

163

TrainY,

164

True

165

TrainBatchSize

166

),

# 呼叫InputFun函式;InputFun函式返回“tf。data。Dataset”物件,這個物件才可以被

167

# train函式識別並帶入模型;由於InputFun函式每次返回BatchSize大小的資料個數,

168

# 因此需要多次執行,前面需要加lambda

169

steps=TrainStep

# 指定模型訓練的步數

170

171

172

# 驗證模型並儲存驗證結果

173

EvalResult=DNNModel。evaluate(input_fn=

lambda

:InputFun(TestX,

174

TestY,

175

False

176

EvalBatchSize

177

178

179

# 列印驗證結果

180

print(

’ev:{}‘

。format(EvalResult))

181

182

# 基於測試資料測試模型精度結果

183

PredictValues=DNNModel。predict(input_fn=

lambda

:InputFunPredict(TestX,

184

PredictBatchSize

185

186

187

188

# 呼叫AccuracyVerification函式,進行精度驗證指標的計算與繪圖

189

AccuracyResult=AccuracyVerification(PredictValues,TestY)

190

PearsonR,R2,RMSE,PredictY=AccuracyResult[

0

],AccuracyResult[

1

],AccuracyResult[

2

],AccuracyResult[

3

191

192

# 呼叫WriteAccuracy函式,將模型所涉及的引數與最終精度結果儲存

193

WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,

194

DecayRate,

’,‘

。join(

’%s‘

%i

for

i

in

HiddenLayer),ActFun,Dropout,LossReduction,

195

BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

想了解更多精彩內容,快來關注瘋狂學習GIS