王桂紅, 潘 棟, 劉向鋒
(沈陽農業(yè)大學 信息與電氣工程學院, 沈陽 110866)
隨著我國農業(yè)現(xiàn)代化的發(fā)展和信息技術的進步,利用農產品市場交易過程中積累的歷史數(shù)據(jù)信息進行短期價格預測對指導農業(yè)生產、消費具有重要意義。例如利用價格預測可以避免農產品價格的劇烈波動導致市場供需失衡的問題[1]。傳統(tǒng)的預測模型有基于回歸分析法建立的回歸模型和基于時間序列法構建的ARIMA模型[2],這類模型通常適用于平穩(wěn)的線性序列數(shù)據(jù),在處理復雜的非線性時序數(shù)據(jù)時,預測值與真實值會有較大偏差。而神經網絡具有良好的并行處理、自組織以及自調整性,其中門控循環(huán)單元網絡GRU(gate recurrent unit,GRU)引入了更新門和重置門的概念,這改變了循環(huán)神經網絡中隱藏狀態(tài)的計算方式[3],因此基于GRU構建的模型可以捕捉時間序列中時間步較大的依賴關系[4],更適合處理海量數(shù)據(jù)和非線性問題[5]。實驗部分首先構建數(shù)據(jù)集,再利用Dropout方法抑制過擬合模型,通過對比實驗調節(jié)訓練輪次、網絡層數(shù)、神經元個數(shù)等超參數(shù)。根據(jù)消融實驗選擇合適的損失函數(shù)與優(yōu)化器,最終建立預測準確率較高與效率最佳的預測模型。
原始的農產品信息通常是不規(guī)范的。本研究以大蒜為例,名稱包括紫皮大蒜、白皮大蒜、山東大蒜等,對于價格沒有顯著差別的同種產品,細分名稱類別對預測精度沒有提升,因而將名稱統(tǒng)稱為大蒜,批量修改數(shù)據(jù)表中名稱列的內容:Update vegetable set name=“大蒜”。
以大蒜的某條價格記錄為例,其字段為“3.3元/公斤”。因為價格預測需保留數(shù)字部分,剔除價格單位,所以從字段左側起,剔除每一個非數(shù)字的字符,“元/公斤”包含4個字符,需要執(zhí)行4次mysql的更新語句:
Update vegetable set vegetable.price=left(vegetable.price, char_length(vegetable.price)-1)where right(vegetable.price,1)not in(′0′,′1′,′2′,′3′,′4′,′5′,′6′,′7′,′8′,′9′)。
使用正則表達式解析農產品產地信息中的字段,例如將“湖北省武漢市江岸區(qū)”劃分為省市區(qū)3級,第1級為湖北(省|自治區(qū)|直轄市),第2級為武漢(市|區(qū)|縣|自治州),第3級為江岸(區(qū)|鄉(xiāng)|鎮(zhèn))。正則表達式如下:
(?〈Province〉[^省]+省|.+自治區(qū))(?〈City〉[^自治州]+自治州|[^市]+市|[^盟]+盟|[^地區(qū)]+地區(qū)|.+區(qū)劃)(?〈County〉[^市]+市|[^縣]+縣|[^旗]+旗|.+區(qū))?(?〈Town〉[^區(qū)]+區(qū)|.+鎮(zhèn))?(?〈Village〉.*)。
時間序列數(shù)據(jù)最關鍵的特征是序列性,價格數(shù)據(jù)隨著時間序列而變化。為保證數(shù)據(jù)的時序一致性,首先將數(shù)據(jù)表中的價格按時間先后進行升序排列,在處理缺失數(shù)據(jù)時,若缺失時間點較少,則使用該點附近的平均值作為該點的數(shù)據(jù)填充[6];若缺失時間點較為密集并且跨度較大,填充失去意義,則將缺失時間點剔除不作處理,對于重復數(shù)據(jù)則取均值進行去重。
通過對原始數(shù)據(jù)進行線性變換,將價格特征數(shù)據(jù)縮放到[0,1][7-8],消除數(shù)據(jù)的量綱與大小帶來的影響。本研究使用的數(shù)據(jù)歸一化方法是最大最小標準化,公式如下:
(1)
式中:x′代表處理完成的數(shù)據(jù);x為當前時刻該特征的真實值;xmax和xmin表示的是原始數(shù)據(jù)集在該時間區(qū)間內的最大值和最小值[9]。在處理完成之后再對數(shù)據(jù)進行反歸一化處理,將數(shù)據(jù)映射到原有數(shù)量級上,從而更直觀地反映數(shù)據(jù)變化情況。
2.1.1 構建數(shù)據(jù)集
經過歸一化的數(shù)據(jù)需要劃分為訓練集和驗證集,為避免出現(xiàn)使用未來數(shù)據(jù)預測歷史數(shù)據(jù)的情況,本研究采用時間序列交叉驗證法代替隨機樣本法來劃分訓練集與驗證集,也稱為滾動交叉驗證[10]。
首先定義變量Training set=dataset[:′2018′].iloc[:, 1∶2].values,把訓練集通過日期索引獲取初始日期到2018年之間的大蒜價格數(shù)據(jù),再根據(jù)下標來獲取第一列的數(shù)據(jù)作為訓練集Training set,將2019年1月、2月的數(shù)據(jù)作為驗證集Test set,訓練集與驗證集占比分別為70%和30%,它們均以Price這一列作為特征值[11]。
以60個時間步為一個樣本,定義一個輸出為大蒜的預測價格,通過for循環(huán)用歸一化以后的數(shù)據(jù)來構建序列數(shù)據(jù)集,參數(shù)為時間步和樣本數(shù)量[12],第一個參數(shù)為i-60,選取第一個維度的大蒜價格作為訓練集的特征向量,再用數(shù)據(jù)集末尾最后的一個樣本作為驗證集的特征向量。
2.1.2 構建初始模型
GRU的網絡容量一般與網絡中可訓練參數(shù)成正比,即神經元數(shù)量和網絡層數(shù)越多,網絡的擬合能力越強,但是存在著訓練速度慢和過擬合的問題[13]。實驗初始模型構建如下:
通過Sequential()創(chuàng)建GRU序列模型model_gru:model_gru = Sequential()。
將模型增加GRU層, input_shape是序列長度,特征為1,驗證設定激活函數(shù)為Tanh。加入全連接層:
model_gru.add(GRU(48,return_sequences=True,input_shape=(x_train.shape[1],1), activation=′Tanh′))。
再調用compile編譯模型, 優(yōu)化器Optimizer使用隨機梯度下降法SGD,設置學習率learning_rate為0.01,損失率decay為1e-7,沖量momentum為0.9,損失函數(shù)采用均方誤差MSE:
model_gru.compile(optimizer=SGD(learning_rate=0.01, decay=1e-7, momentum=0.9), loss=′mse′)
預測的是一個值,輸出層數(shù)為1: model_gru.add(Dense(1))。
將驗證集Training set作為參數(shù),最終通過預測函數(shù)得出預測值GRU_predict。
2.1.3 模型優(yōu)化方法
Dropout方法修改了訓練中的學習過程, 通過禁止特征檢測器之間的相互作用,減輕了模型對于局部特征的依賴程度,同時也提高了模型的泛化能力,提升網絡的性能,避免了過擬合的情況[14]。
將GRU網絡加上Dropout層,固定輸入輸出神經元不變,通過model_gru.add(Dropout(0.2))來隨機刪除運行時批次中的20%隱藏神經元,減少隱藏層節(jié)點間的相互作用。
2.2.1 對比實驗
在分析數(shù)據(jù)量的大小與特征的基礎上,確定批次大小batch_size為32,將訓練輪次、網絡層數(shù)等超參進行組合,設計對比實驗,具體參數(shù)設置見表1。
表1 參數(shù)名稱與參數(shù)值表
使用fit函數(shù)訓練模型,在GRU層與全連接層均為1,神經元為48的情況下,不同訓練輪次的運行結果如圖2所示。
(a) 50訓練輪次損失(b) 100訓練輪次損失(c) 200訓練輪次損失(d)最優(yōu)訓練輪次損失
(a) 16個神經元訓練結果(b) 32個神經元訓練結果(c) 48個神經元訓練結果
損失Loss為模型誤差,實驗誤差率均以百分比衡量再化簡符號,例如9.95%的誤差定義為0.099 5。由圖1(a)、圖1(b)和圖1(c)可知,當Epoch為50時,誤差為0.099 5,當Epoch為100時,誤差為0.083 6,當Epoch為200時,誤差為0.086 4。因此確定最佳訓練輪次為100,將模型按最佳輪次進行迭代,如圖1(d)所示,最終誤差降到0.036 5。固定網絡層數(shù),組合不同神經元個數(shù)的多次實驗,當網絡層數(shù)均為1時,實驗結果見表2。
表2 神經元個數(shù)與損失值關系
由表2可知,在保持訓練輪次和模型層數(shù)不變的情況下,當神經元個數(shù)為16時,誤差為0.084 5;當神經元個數(shù)為32時,誤差為0.073 6;當神經元個數(shù)為48時,誤差為0.081 4,即最佳神經元個數(shù)為32。不同神經元個數(shù)運行的預測結果如圖3所示。
運行結果展示了真實價格與預測價格的走勢和對比情況,藍色折線為真實值,橙色折線為預測值。其中圖2(a)展示的是16個神經元的訓練結果,預測曲線較為平穩(wěn),在價格峰值和谷值時,預測值與實際值差距較大,圖2(b)為32個神經元的訓練結果,預測值能準確地描述出價格波動的情況,比圖2(c)的48個神經元的預測結果更貼近真實值曲線。將GRU層數(shù)、全連接層數(shù)與神經元個數(shù)進行組合實驗,結果表明神經元個數(shù)為32時模型精度最高。通過多次組合實驗,得出最佳超參數(shù)組合為:訓練輪次100、GRU與全連接均為3層、神經元個數(shù)為32。
2.2.2 消融實驗
初始模型的優(yōu)化器使用的是SGD,即無動量的隨機梯度下降,指定了學習率和衰減值,SGD的高方差振蕩使網絡難以穩(wěn)定收斂。Adam在SGD的基礎上增加一階動量和二階動量[15],在迭代的過程中學習率可隨梯度的變化而動態(tài)調整。通過優(yōu)化相關方向的訓練和弱化無關方向的振蕩,將更新向量的分量添加到當前更新向量,達到加速訓練的效果。因此,將優(yōu)化器更換為Adam來研究動量對于網絡的影響。
初始模型使用的激活函數(shù)為Tanh,在訓練時出現(xiàn)端值并趨于飽和時會導致訓練速度減慢,將激活函數(shù)更換為非飽和激活函數(shù)Relu來研究減輕梯度消失對模型的影響。
使用已確定的超參數(shù)再對優(yōu)化器和激活函數(shù)進行組合,設計消融實驗,各參考設置見表3。
表3 優(yōu)化器與激活函數(shù)組合表
通過更換優(yōu)化器和激活函數(shù)完成消融實驗,實驗誤差率如圖3所示。實驗組的誤差率分別為:0.058 3,0.047 6,0.055 3,0.043 5,其中實驗4組的誤差率最小為0.043 5。
圖3 實驗誤差率
圖4顯示了實驗的運行耗時,4組實驗運行時間分別為:14.8,12.5,13.6,10.8 min。其中第4組運行時間最短,為10.8 min。模型預測數(shù)據(jù)的準確程度如圖5所示。
圖4 實驗運行時間
(a) 實驗1組(b) 實驗2組(c) 實驗3組(d) 實驗4組
從圖5可以看出,預測價格和真實值大多集中在3元到4.5元之間。圖5(a)的實驗1組中預測曲線整體符合真實價格走勢情況,但當價格劇烈波動產生極大值與極小值時,預測曲線表現(xiàn)得不夠明顯;圖5(b)的實驗2組與1組的前期預測曲線較為接近,但2組的預測值偏高,后期預測值更接近真實值;圖5(c)的實驗3組整體預測值偏低,偏離實際值的峰值曲線較多,比較符合價格下跌的曲線;圖5(d)的實驗4組不論是價格上升還是下降,預測曲線都較好地描述了價格波動的特征。實驗表明實驗4組的預測效果最好,即在增加動量和使用非飽和激活函數(shù)并且減輕梯度消失的情況下,模型的準確度較高。因此,模型的優(yōu)化器應選擇Adam,激活函數(shù)選擇Relu。
通過對比實驗與消融實驗對初始模型進行調節(jié)優(yōu)化,最終預測模型的結構與相關參數(shù)如下:神經網絡使用GRU、訓練輪次為100次、GRU層數(shù)和全連接層數(shù)均為3層、神經元個數(shù)為32個,優(yōu)化器使用Adam,激活函數(shù)選取Relu。最優(yōu)超參的GRU模型預測準確率較高并且運行耗時短。本研究搭建的最佳預測模型的普適性強,將大蒜的價格時序數(shù)據(jù)替換為其他農產品的價格時序數(shù)據(jù),亦可做出相應的短期價格預測。