主頁 > 後端開發 > Python TensorFlow深度學習回歸代碼:DNNRegressor

Python TensorFlow深度學習回歸代碼:DNNRegressor

2023-02-03 06:31:10 後端開發

??本文介紹基于Python語言中TensorFlowtf.estimator介面,實作深度學習神經網路回歸的具體方法,

目錄
  • 1 寫在前面
  • 2 代碼分解介紹
    • 2.1 準備作業
    • 2.2 引數配置
    • 2.3 原有模型洗掉
    • 2.4 資料匯入與資料劃分
    • 2.5 Feature Columns定義
    • 2.6 模型優化方法構建與模型結構構建
    • 2.7 模型訓練
    • 2.8 模型驗證與測驗
    • 2.9 精度評定、擬合影像繪制與模型引數與精度結果保存
  • 3 詳細代碼

1 寫在前面

??1. 本文介紹的是基于TensorFlow tf.estimator介面的深度學習網路,而非TensorFlow 2.0中常用的Keras介面;關于Keras介面實作深度學習回歸,我們將在下一篇博客中介紹,

??2. 本文代碼以DNNRegressor回歸為例;而由于基于 tf.estimator介面的深度學習回歸分類整體較為類似,因此二者具有觸類旁通的效果,

??3. 本文第二部分為代碼的分解介紹,第三部分為完整代碼,

??4. 相關版本資訊:Python版本:3.8.5TensorFlow版本:2.4.1;編譯器版本:Spyder 4.1.5

2 代碼分解介紹

2.1 準備作業

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

import os
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

??其次,基于TensorFlow的代碼往往會輸出較多的日志資訊,從而使得我們對代碼執行情況的了解受到一定影響,代碼輸出的日志資訊有四種,依據嚴重程度由低到高排序:INFO(通知)<WARNING(警告)<ERROR(錯誤)<FATAL(致命的);我們可以通過如下代碼來對TensorFlow的輸出日志資訊加以約束,

os.environ['TF_CPP_MIN_LOG_LEVEL']='3'

??其中,3代表只輸出FATAL資訊,但要注意,這句代碼需要放在import tensorflow的前面:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

2.2 引數配置

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

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

# 將各類變數放在一個位置集中定義,十分有利于機器學習等變數較多的代碼
MyModelPath="G:/CropYield/03_DL/02_DNNModle" # 確定每一次訓練所得模型保存的位置
MyDataPath="G:/CropYield/03_DL/00_Data/AllDataAll.csv" # 確定輸入資料的位置
MyResultSavePath="G:/CropYield/03_DL/03_OtherResult/EvalResult54.xlsx" # 確定模型精度結果(RMSE等)與模型引數保存的位置
TestSize=0.2 # 確定資料中測驗集所占比例
RandomSeed=np.random.randint(low=24,high=25) # 確定劃分訓練集與測驗集的亂數種子
OptMethod='Adam' # 確定模型所用的優化方法
LearningRate=0.01 # 確定學習率
DecayStep=200 # 確定學習率下降的步數
DecayRate=0.96 # 確定學習率下降比率
HiddenLayer=[64,128] # 確定隱藏層數量與每一層對應的神經元數量
ActFun='tf.nn.relu' # 確定激活函式
Dropout=0.3 # 確定Dropout的值
LossReduction='tf.compat.v1.ReductionV2.SUM_OVER_BATCH_SIZE' # 指定每個批次訓練誤差的減小方法
BatchNorm='False' # 確定是否使用Batch Normalizing
TrainBatchSize=110 # 確定訓練資料一個Batch的大小
TrainStep=3000 # 確定訓練資料的Step數量
EvalBatchSize=1 # 確定驗證資料一個Batch的大小
PredictBatchSize=1 # 確定預測資料(即測驗集)一個Batch的大小

2.3 原有模型洗掉

??DNNRegressor每執行一次,便會在指定路徑中保存當前運行的模型,為保證下一次模型保存時不受上一次模型運行結果干擾,我們可以將模型檔案夾內的全部檔案洗掉,

# DeleteOldModel函式,洗掉上一次運行所保存的模型
def DeleteOldModel(ModelPath):
    AllFileName=os.listdir(ModelPath) # 獲取ModelPath路徑下全部檔案與檔案夾
    for i in AllFileName:
        NewPath=os.path.join(ModelPath,i) # 分別將所獲取的檔案或檔案夾名稱與ModelPath路徑組合
        if os.path.isdir(NewPath): # 若組合后的新路徑是一個檔案夾
            DeleteOldModel(NewPath) # 遞回呼叫DeleteOldModel函式
        else:
            os.remove(NewPath) # 若不是一個新的檔案夾,而是一個檔案,那么就洗掉

# 呼叫DeleteOldModel函式,洗掉上一次運行所保存的模型
DeleteOldModel(MyModelPath)

??需要注意,以上代碼僅洗掉指定路徑下的檔案,檔案夾不洗掉,大家如果需要將檔案夾也同時洗掉,修改以上代碼函式中的后面幾句即可,

2.4 資料匯入與資料劃分

??我的資料已經保存在了.csv檔案中,因此可以用pd.read_csv直接讀取,

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

# LoadData函式,加載全部資料
def LoadData(DataPath):
    MyData=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/pd.read_csv(DataPath,names=['EVI0610','EVI0626','EVI0712','EVI0728','EVI0813','EVI0829',
                                       'EVI0914','EVI0930','EVI1016','Lrad06','Lrad07','Lrad08',
                                       'Lrad09','Lrad10','Prec06','Prec07','Prec08','Prec09',
                                       'Prec10','Pres06','Pres07','Pres08','Pres09','Pres10',
                                       'SIF161','SIF177','SIF193','SIF209','SIF225','SIF241',
                                       'SIF257','SIF273','SIF289','Shum06','Shum07','Shum08',
                                       'Shum09','Shum10','SoilType','Srad06','Srad07','Srad08',
                                       'Srad09','Srad10','Temp06','Temp07','Temp08','Temp09',
                                       'Temp10','Wind06','Wind07','Wind08','Wind09','Wind10',
                                       'Yield'],header=0) # 加載DataPath路徑所指定的資料,names中的內容為各列的名稱
    return MyData

# 初始資料處理
AllXY=LoadData(MyDataPath) # 呼叫LoadData函式,獲取資料
Label={"Yield":AllXY.pop("Yield")} # 將因變數從全部資料中提取出
AllX,AllY=AllXY,(pd.DataFrame(Label)) # 將自變數與因變數分離

# 劃分資料訓練集與測驗集
TrainX,TestX,TrainY,TestY=train_test_split(AllX,
                                           AllY,
                                           test_size=TestSize, # 指定資料中測驗集所占比例
                                           random_state=RandomSeed # 指定劃分訓練集與測驗集的亂數種子
                                           )

2.5 Feature Columns定義

??Feature Columns就是一個橋梁,聯系你的初始資料與模型;其好比一個名單,模型拿著這個名單到你的資料(即本文2.4部分你匯入的資料)中按列的名稱一一搜索,若初始資料中的某列名稱在Feature Columns里,那么模型就會把初始資料中這一列的資料全部拿到自己這里,進行訓練,

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

??在這里需要注意的是,只有連續數值變數才可以用tf.feature_column.numeric_column處理;若是類別變數可以對其加以獨熱編碼等操作,

# estimator介面中的模型需要用“Feature columns”物件作為輸入資料,只有這樣模型才知道讀取哪些資料
FeatureColumn=[] # 定義一個新的“Feature columns”物件
for key in AllX.keys():
    FeatureColumn.append(tf.feature_column.numeric_column(key=key)) # 將全部因變數資料(需要均為連續變數)匯入

2.6 模型優化方法構建與模型結構構建

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

# 定義模型優化方法
# Optimizer=OptMethod # 優化方法選用OptMethod所指定的方法
Optimizer=lambda:tf.keras.optimizers.Adam(
    learning_rate=tf.compat.v1.train.exponential_decay(learning_rate=LearningRate, # 初始學習率
                                                       global_step=tf.compat.v1.train.get_global_step(),
                                                       # 全域步數,用以計算已經衰減后的學習率
                                                       # get_global_step()函式自動獲取當前的已經執行的步數
                                                       decay_steps=DecayStep, # 學習率下降完成的指定步數
                                                       decay_rate=DecayRate # 衰減率
                                                       ) # 選用基于學習率指數下降的Adam方法,此舉有助于降低過擬合風險
                                                         # 這一函式回傳每次對應的學習率
    )

??以上代碼中有兩個Optimizer=,第一個是直接輸入優化方法的名稱即可,名稱包括:'Adagrad', 'Adam', 'Ftrl', 'RMSProp', SGD';默認為Adagrad

??第二個是在選擇了優化方法的基礎上,配置其他資訊,例如第二個,其代表著學習率指數下降的Adam優化方法,其中,tf.compat.v1.train.exponential_decay可視作一個計算每次訓練學習率的函式,他回傳的是每一次對應的學習率,可能這么說不太好理解,看這個公式:其回傳值為learning_rate *decay_rate ^ (global_step / decay_steps),是不是就明白啦,

??我們選擇第二個優化方法,因此把第一個注釋掉,

??隨后,我們定義模型的結構,

# 基于DNNRegressor構建深度學習模型
DNNModel=tf.estimator.DNNRegressor(feature_columns=FeatureColumn, # 指定模型所用的“Feature columns”物件
                                   hidden_units=HiddenLayer, # 指定隱藏層數量與每一層對應的神經元數量
                                   optimizer=Optimizer, # 指定模型所用的優化方法                                  
                                   activation_fn=eval(ActFun), # 指定激活函式
                                   dropout=Dropout, # 指定Dropout的值
                                   label_dimension=1, # 輸出資料的維度,即因變數的個數
                                   model_dir=MyModelPath, # 指定每一次訓練所得模型保存的位置
                                   # loss_reduction=eval(LossReduction), # 指定每個批次訓練誤差的減小方法
                                   batch_norm=eval(BatchNorm) # 指定是否使用Batch Normalizing
                                   )

??模型的構建,對照著代碼上的注釋,就比較好理解了;其中,我把loss_reduction注釋掉,是因為可能由于TensorFlow版本的問題,其總是報錯,所以就用默認的值就好;而最后一個batch_norm,決定了是否進行Batch NormalizingBatch Normalizing可以保持深度神經網路在每一層保持相同分布,從而加快網路收斂與增強網路穩固性,

??其它引數可以參考官方網站,這里暫時不再贅述,

2.7 模型訓練

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

# 基于訓練資料訓練模型
DNNModel.train(input_fn=lambda:InputFun(TrainX,
                                        TrainY,
                                        True,
                                        TrainBatchSize
                                        ), # 呼叫InputFun函式;InputFun函式回傳“tf.data.Dataset”物件,這個物件才可以被
                                           # train函式識別并帶入模型;由于InputFun函式每次回傳BatchSize大小的資料個數,
                                           # 因此需要多次執行,前面需要加lambda
               steps=TrainStep # 指定模型訓練的步數
               )

??我們可以這么理解:在train函式中,只有一個引數input_fn;而這個引數的輸入,又是一個新的函式——這個新的函式就是大名鼎鼎的input function了,

??他長這個樣子:

# InputFun函式,訓練資料與驗證資料所用的Input函式
def InputFun(Features,Labels,Training,BatchSize):
    Datasets=tf.data.Dataset.from_tensor_slices((dict(Features),Labels)) # 對資料加以加載
    if Training:
        Datasets=Datasets.shuffle(1000).repeat() # 對于訓練資料,需要打亂(shuffle)、重復(repeat)
    return Datasets.batch(BatchSize) # 將經過上述處理后的資料以每次BatchSize個輸出

??那我們首先就看input function——也就是代碼中的InputFun函式,其實這個函式的用處很簡單,用官網的話說,其就是用來輸入模型支持的資料型別的——只有經過input function處理后,資料才可以被DNNRegressor識別,聽上去這么厲害,它到底是如何操作的呢?

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

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

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

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

tuple=(features,label)
features={'溫度':np.array([10,20]),'降水':np.array([15,25])}
label=np.array([100,150])

??怎么樣,是不是明白啦,

??理解了之后,我們繼續看InputFun函式,首先,tf.data.Dataset.from_tensor_slices用來將輸入的資料加載并轉換為Datase的形式;隨后,如果是訓練狀態下,那么資料會進行打亂.shuffle(1000)——相當于對資料加以洗牌,防止初始資料具有一定的趨勢,例如如果我們做分類,其中初始資料的前80%都是第一類,后20%都是第二類,那么如果我們不打亂資料,會使得用前80%資料訓練出來的結果都是第一類(即模型只認識第一類),在后20%進行測驗時,所得結果也全都為第一類;所以要打亂,其中的1000buffer_size引數,這個資料必須要比你的資料樣本個數大,至于.shuffle(1000)這個函式的原理我一直沒有搞明白,大家感興趣的話可以加以進一步了解,

??.repeat()則是對資料集加以重復,之所以要重復,是因為我們需要對全部資料訓練好幾輪(即好幾個Epoch),因此要對初始資料加以重復,

??隨后,用.batch()函式輸出BatchSize個資料,也就是一批資料;其中BatchSize就是每一批資料的個數,

??這個就是InputFun函式,再看train函式函式:大家也看出來了,這個InputFun函式是每次輸出一批(BatchSize個)資料;而我們訓練的時候,肯定是要一批一批不停輸入資料的,因此這就解釋了為什么InputFun函式前有一個lambda——因為InputFun函式要把處理后的資料分多次傳給train

2.8 模型驗證與測驗

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

# InputFunPredict函式,測驗資料所用的Input函式
def InputFunPredict(Features,BatchSize):
    return tf.data.Dataset.from_tensor_slices(dict(Features)).batch(BatchSize) # 對資料加以加載,以每次BatchSize個輸出    

# 驗證模型并保存驗證結果
EvalResult=DNNModel.evaluate(input_fn=lambda:InputFun(TestX,
                                                      TestY,
                                                      False,
                                                      EvalBatchSize
                                                      )
                             )
# 列印驗證結果
print('ev:{}'.format(EvalResult))

# 基于測驗資料測驗模型精度結果
PredictValues=DNNModel.predict(input_fn=lambda:InputFunPredict(TestX,
                                                               PredictBatchSize
                                                               )
                               )

??其中,驗證時.evaluate所用的InputFun函式其實和訓練集所用的是一樣的函式,只不過驗證時不需要進行打亂.shuffle(1000)和重復.repeat()操作;而測驗時.predictInputFun函式則是新的,其只需要輸入自變數、無需輸入因變數,

2.9 精度評定、擬合影像繪制與模型引數與精度結果保存

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

# AccuracyVerification函式,進行精度驗證指標的計算與繪圖
def AccuracyVerification(PredictLabels,TestLabels):
    value=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/0
    PredictValuesList=[]
    for k in PredictLabels:
        value=k.get('predictions')[0]
        PredictValuesList.append(value)
    TestLabels=TestLabels.values.tolist()
    TestYList=sum(TestLabels,[])
    # 以上為獲取測驗資料的因變數與模型預測所得的因變數
    Pearsonr=stats.pearsonr(TestYList,PredictValuesList) # 計算皮爾遜相關系數
    R2=metrics.r2_score(TestYList,PredictValuesList) # 計算R方
    RMSE=metrics.mean_squared_error(TestYList,PredictValuesList)**0.5 # 計算RMSE
    plt.cla()
    plt.plot(TestYList,PredictValuesList,'r*')
    plt.xlabel('Actual Values')
    plt.ylabel('Predicted Values')
    # 以上為繪制擬合影像
    print('Pearson correlation coefficient is {0}, and RMSE is {1}.'.format(Pearsonr[0],RMSE))
    return (Pearsonr[0],R2,RMSE,PredictValuesList)

# WriteAccuracy函式,將模型所涉及的引數與最終精度結果保存
def WriteAccuracy(*WriteVar):
    ExcelData=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/openpyxl.load_workbook(WriteVar[0])
    SheetName=ExcelData.get_sheet_names() # 獲取全部Sheet
    WriteSheet=ExcelData.get_sheet_by_name(SheetName[0]) # 獲取指定Sheet
    WriteSheet=ExcelData.active # 激活指定Sheet
    MaxRowNum=WriteSheet.max_row # 獲取指定Sheet對應第一個空行
    for i in range(len(WriteVar)-1):
        exec("WriteSheet.cell(MaxRowNum+1,i+1).value=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/WriteVar[i+1]") # 用exec執行陳述句,寫入資訊
    ExcelData.save(WriteVar[0]) # 保存檔案

# 呼叫AccuracyVerification函式,進行精度驗證指標的計算與繪圖
AccuracyResult=AccuracyVerification(PredictValues,TestY)
PearsonR,R2,RMSE,PredictY=AccuracyResult[0],AccuracyResult[1],AccuracyResult[2],AccuracyResult[3]

# 呼叫WriteAccuracy函式,將模型所涉及的引數與最終精度結果保存
WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,
              DecayRate,','.join('%s' %i for i in HiddenLayer),ActFun,Dropout,LossReduction,
              BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

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

3 詳細代碼

# -*- coding: utf-8 -*-
"""
Created on Tue Feb 23 16:13:21 2021

@author: Chutj
"""

# 加載必要的庫、包等
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

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

# DeleteOldModel函式,洗掉上一次運行所保存的模型
def DeleteOldModel(ModelPath):
    AllFileName=os.listdir(ModelPath) # 獲取ModelPath路徑下全部檔案與檔案夾
    for i in AllFileName:
        NewPath=os.path.join(ModelPath,i) # 分別將所獲取的檔案或檔案夾名稱與ModelPath路徑組合
        if os.path.isdir(NewPath): # 若組合后的新路徑是一個檔案夾
            DeleteOldModel(NewPath) # 遞回呼叫DeleteOldModel函式
        else:
            os.remove(NewPath) # 若不是一個新的檔案夾,而是一個檔案,那么就洗掉

# LoadData函式,加載全部資料
def LoadData(DataPath):
    MyData=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/pd.read_csv(DataPath,names=['EVI0610','EVI0626','EVI0712','EVI0728','EVI0813','EVI0829',
                                       'EVI0914','EVI0930','EVI1016','Lrad06','Lrad07','Lrad08',
                                       'Lrad09','Lrad10','Prec06','Prec07','Prec08','Prec09',
                                       'Prec10','Pres06','Pres07','Pres08','Pres09','Pres10',
                                       'SIF161','SIF177','SIF193','SIF209','SIF225','SIF241',
                                       'SIF257','SIF273','SIF289','Shum06','Shum07','Shum08',
                                       'Shum09','Shum10','SoilType','Srad06','Srad07','Srad08',
                                       'Srad09','Srad10','Temp06','Temp07','Temp08','Temp09',
                                       'Temp10','Wind06','Wind07','Wind08','Wind09','Wind10',
                                       'Yield'],header=0) # 加載DataPath路徑所指定的資料,names中的內容為各列的名稱
    return MyData

# InputFun函式,訓練資料與驗證資料所用的Input函式
def InputFun(Features,Labels,Training,BatchSize):
    Datasets=tf.data.Dataset.from_tensor_slices((dict(Features),Labels)) # 對資料加以加載
    if Training:
        Datasets=Datasets.shuffle(1000).repeat() # 對于訓練資料,需要打亂(shuffle)、重復(repeat)
    return Datasets.batch(BatchSize) # 將經過上述處理后的資料以每次BatchSize個輸出

# InputFunPredict函式,測驗資料所用的Input函式
def InputFunPredict(Features,BatchSize):
    return tf.data.Dataset.from_tensor_slices(dict(Features)).batch(BatchSize) # 對資料加以加載,以每次BatchSize個輸出

# AccuracyVerification函式,進行精度驗證指標的計算與繪圖
def AccuracyVerification(PredictLabels,TestLabels):
    value=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/0
    PredictValuesList=[]
    for k in PredictLabels:
        value=k.get('predictions')[0]
        PredictValuesList.append(value)
    TestLabels=TestLabels.values.tolist()
    TestYList=sum(TestLabels,[])
    # 以上為獲取測驗資料的因變數與模型預測所得的因變數
    Pearsonr=stats.pearsonr(TestYList,PredictValuesList) # 計算皮爾遜相關系數
    R2=metrics.r2_score(TestYList,PredictValuesList) # 計算R方
    RMSE=metrics.mean_squared_error(TestYList,PredictValuesList)**0.5 # 計算RMSE
    plt.cla()
    plt.plot(TestYList,PredictValuesList,'r*')
    plt.xlabel('Actual Values')
    plt.ylabel('Predicted Values')
    # 以上為繪制擬合影像
    print('Pearson correlation coefficient is {0}, and RMSE is {1}.'.format(Pearsonr[0],RMSE))
    return (Pearsonr[0],R2,RMSE,PredictValuesList)

# WriteAccuracy函式,將模型所涉及的引數與最終精度結果保存
def WriteAccuracy(*WriteVar):
    ExcelData=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/openpyxl.load_workbook(WriteVar[0])
    SheetName=ExcelData.get_sheet_names() # 獲取全部Sheet
    WriteSheet=ExcelData.get_sheet_by_name(SheetName[0]) # 獲取指定Sheet
    WriteSheet=ExcelData.active # 激活指定Sheet
    MaxRowNum=WriteSheet.max_row # 獲取指定Sheet對應第一個空行
    for i in range(len(WriteVar)-1):
        exec("WriteSheet.cell(MaxRowNum+1,i+1).value=https://www.cnblogs.com/fkxxgis/archive/2023/02/02/WriteVar[i+1]") # 用exec執行陳述句,寫入資訊
    ExcelData.save(WriteVar[0]) # 保存檔案


# ===============*** 代碼由此開始執行 ***===============
#      ++++++++++--- 建議由這里開始看 ---++++++++++

# 將各類變數放在一個位置集中定義,十分有利于機器學習等變數較多的代碼
MyModelPath="G:/CropYield/03_DL/02_DNNModle" # 確定每一次訓練所得模型保存的位置
MyDataPath="G:/CropYield/03_DL/00_Data/AllDataAll.csv" # 確定輸入資料的位置
MyResultSavePath="G:/CropYield/03_DL/03_OtherResult/EvalResult54.xlsx" # 確定模型精度結果(RMSE等)與模型引數保存的位置
TestSize=0.2 # 確定資料中測驗集所占比例
RandomSeed=np.random.randint(low=24,high=25) # 確定劃分訓練集與測驗集的亂數種子
OptMethod='Adam' # 確定模型所用的優化方法
LearningRate=0.01 # 確定學習率
DecayStep=200 # 確定學習率下降的步數
DecayRate=0.96 # 確定學習率下降比率
HiddenLayer=[64,128] # 確定隱藏層數量與每一層對應的神經元數量
ActFun='tf.nn.relu' # 確定激活函式
Dropout=0.3 # 確定Dropout的值
LossReduction='tf.compat.v1.ReductionV2.SUM_OVER_BATCH_SIZE' # 指定每個批次訓練誤差的減小方法
BatchNorm='False' # 確定是否使用Batch Normalizing
TrainBatchSize=110 # 確定訓練資料一個Batch的大小
TrainStep=3000 # 確定訓練資料的Step數量
EvalBatchSize=1 # 確定驗證資料一個Batch的大小
PredictBatchSize=1 # 確定預測資料(即測驗集)一個Batch的大小

# 呼叫DeleteOldModel函式,洗掉上一次運行所保存的模型
DeleteOldModel(MyModelPath)

# 初始資料處理
AllXY=LoadData(MyDataPath) # 呼叫LoadData函式,獲取資料
Label={"Yield":AllXY.pop("Yield")} # 將因變數從全部資料中提取出
AllX,AllY=AllXY,(pd.DataFrame(Label)) # 將自變數與因變數分離

# 劃分資料訓練集與測驗集
TrainX,TestX,TrainY,TestY=train_test_split(AllX,
                                           AllY,
                                           test_size=TestSize, # 指定資料中測驗集所占比例
                                           random_state=RandomSeed # 指定劃分訓練集與測驗集的亂數種子
                                           )

# estimator介面中的模型需要用“Feature columns”物件作為輸入資料,只有這樣模型才知道讀取哪些資料
FeatureColumn=[] # 定義一個新的“Feature columns”物件
for key in AllX.keys():
    FeatureColumn.append(tf.feature_column.numeric_column(key=key)) # 將全部因變數資料(需要均為連續變數)匯入

# 定義模型優化方法
# Optimizer=OptMethod # 優化方法選用OptMethod所指定的方法
Optimizer=lambda:tf.keras.optimizers.Adam(
    learning_rate=tf.compat.v1.train.exponential_decay(learning_rate=LearningRate, # 初始學習率
                                                       global_step=tf.compat.v1.train.get_global_step(),
                                                       # 全域步數,用以計算已經衰減后的學習率
                                                       # get_global_step()函式自動獲取當前的已經執行的步數
                                                       decay_steps=DecayStep, # 學習率下降完成的指定步數
                                                       decay_rate=DecayRate # 衰減率
                                                       ) # 選用基于學習率指數下降的Adam方法,此舉有助于降低過擬合風險
                                                         # 這一函式回傳每次對應的學習率
    )


# 基于DNNRegressor構建深度學習模型
DNNModel=tf.estimator.DNNRegressor(feature_columns=FeatureColumn, # 指定模型所用的“Feature columns”物件
                                   hidden_units=HiddenLayer, # 指定隱藏層數量與每一層對應的神經元數量
                                   optimizer=Optimizer, # 指定模型所用的優化方法                                  
                                   activation_fn=eval(ActFun), # 指定激活函式
                                   dropout=Dropout, # 指定Dropout的值
                                   label_dimension=1, # 輸出資料的維度,即因變數的個數
                                   model_dir=MyModelPath, # 指定每一次訓練所得模型保存的位置
                                   # loss_reduction=eval(LossReduction), # 指定每個批次訓練誤差的減小方法
                                   batch_norm=eval(BatchNorm) # 指定是否使用Batch Normalizing
                                   )

# tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.INFO) # 將INFO級別的日志資訊顯示到螢屏

# 基于訓練資料訓練模型
DNNModel.train(input_fn=lambda:InputFun(TrainX,
                                        TrainY,
                                        True,
                                        TrainBatchSize
                                        ), # 呼叫InputFun函式;InputFun函式回傳“tf.data.Dataset”物件,這個物件才可以被
                                           # train函式識別并帶入模型;由于InputFun函式每次回傳BatchSize大小的資料個數,
                                           # 因此需要多次執行,前面需要加lambda
               steps=TrainStep # 指定模型訓練的步數
               ) 

# 驗證模型并保存驗證結果
EvalResult=DNNModel.evaluate(input_fn=lambda:InputFun(TestX,
                                                      TestY,
                                                      False,
                                                      EvalBatchSize
                                                      )
                             )
# 列印驗證結果
print('ev:{}'.format(EvalResult))

# 基于測驗資料測驗模型精度結果
PredictValues=DNNModel.predict(input_fn=lambda:InputFunPredict(TestX,
                                                               PredictBatchSize
                                                               )
                               )

# 呼叫AccuracyVerification函式,進行精度驗證指標的計算與繪圖
AccuracyResult=AccuracyVerification(PredictValues,TestY)
PearsonR,R2,RMSE,PredictY=AccuracyResult[0],AccuracyResult[1],AccuracyResult[2],AccuracyResult[3]

# 呼叫WriteAccuracy函式,將模型所涉及的引數與最終精度結果保存
WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,
              DecayRate,','.join('%s' %i for i in HiddenLayer),ActFun,Dropout,LossReduction,
              BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

??至此,大功告成,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542859.html

標籤:其他

上一篇:云原生場景下實作編譯加速

下一篇:若依-更換資料庫-sqlite

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more