MATLAB强化学习入门——三、深度Q学习与神经网络工具箱(matlab入门图文教程)
零、為什么需要深度Q學習
上一期的文章《網格迷宮、Q-learning算法、Sarsa算法》的末尾,我們提到了Q學習固有的缺陷:由于智能體(agent)依賴以狀態-動作對為自變量的Q函數表(Q Function Table)來形成對當前狀態的估計,并以此為依據利用策略π選擇動作。Q函數表就必須包含智能體在環境中所可能出現的所有動作-狀態對及其對應Q值。顯然,當一個多步決策問題變得足夠復雜甚至變為連續決策或控制問題時,Q學習本身是無力應對的。例如,對于復雜的多步決策問題,龐大而結構復雜的Q表將變得難以存儲和讀取;將網格迷宮的長、寬各擴大10倍,Q表則變成原來的100倍。對于連續決策/控制問題時,Q表更是無法記錄所有的狀態。
 那么,如何解決這一問題呢?
 一個直截的想法就是,選擇某個多元函數,逼近Q表中“自變量”動作-狀態對與“因變量”Q值形成的關系。但這樣做依然存在問題:對于不同的強化學習問題,Q表中的數據呈現出各異的曲線特性,只有找到符合Q表數據的函數形式,才可能良好的逼近Q表。選擇傳統函數進行逼近,顯然是很難實現編程自動化的。
 神經網絡(Neural Network)恰恰是這么一種有別于傳統函數逼近的解決方案。而從數學的角度講,神經網絡本質上就是一種強大的非線性函數逼近器。將神經網絡與Q學習結合起來,就得到了能夠解決更復雜問題的Q-Network以及使用深度神經網絡的Deep-Q-Network (DQN)。
 Deep-Q-Learning的算法究竟是什么樣的?浙江大學的《機器學習和人工智能》MOOC有著大致的講解。而如何實現Deep-Q-Learning?莫煩Python以及北理工的MOOC也給出了Python語言的詳細示范。
 盡管有關Deep-Q-Learning的程序和講解已經很多權威且易懂的內容;準確的理解Deep-Q-Learning算法,并在MatLab上實現,則是完成強化學習控制這個最終目標的關鍵。具體到Deep-Q-Learning的實現上,它不僅與之前的Q-Learning在程序結構上有著相當大的區別,直接將它應用于連續控制問題也會是非常跳躍的一步。因此,在這一期的文章里,問題將聚焦在前后兩個問題之間:如何使用神經網絡讓智能體走好網格迷宮?
 將這個問題再細分開來,則包括兩部分:
- 如何使用MatLab的神經網絡工具箱?
 - 如何實現深度Q學習算法?
 
第三期主要包含兩部分內容,第一部分即上文,簡要介紹了深度Q學習的存在基礎,另一部分則解決第一個小問題,討論一下MatLab神經網絡工具箱的使用。在第四期,我們再詳細聊一聊深度Q學習在網格迷宮中的實現。
一、神經網絡工具箱(Neural Network Toolbox)
MatLab自版本R2006a就開始提供自定義構建神經網絡模型的函數;到目前為止,除機器學習方向科研人員外,Matlab的神經網絡工具箱已經能滿足其余使用者對神經網絡模型的絕大部分需求。用戶除去可以使用feedforwardnet()函數構建定制的全連接前饋神經網絡外, 還可以直接調用封裝好的經典卷積神經網絡(convolutional neural network)模型ALEXnet、VGG16、Googlenet等。
 本文不打算詳細介紹或討論關于神經網絡方面的理論知識,作者本人自忖也沒有綜論這方面知識的能力和水平。如果想要進一步了解這方面知識的,可以移步浙江大學《機器學習和人工智能》MOOC以及周志華教授的西瓜書。盡管如此,一些概念還是需要在此闡明一下,以方便之后Deep-Q-Network的實現。
| 圖1 神經網絡模型 | 
|---|
簡言之,神經網絡結構有多層的神經元單元及相互之間的連接構成。對于全連接神經網絡,任意一層A的任意一個神經元a_1都存在與下一層B的所有神經元b_i的連接,A層內的神經元則不相互連接;換句話說,B層的任意一個神經元b_1的輸入為上一層所有神經元輸出的加權總和。假設A層有m個神經元,B層有n個,則B層第j個神經元的輸入為:
 
 其中w_ij為神經元對的連接權重。如上式所表示的,不同的權重反映了兩神經元之間聯系的緊密程度。在B層的神經元內部,則將輸入IN_bj通過例如Sigmoid和Relu等函數將輸入進行非線性變換得到輸出,再傳輸至下一層。通過如上的傳遞方式,前饋神經網絡將輸入從第一層映射至最后層獲得輸出,這一結果即為神經網絡的預測輸出。
 對于一個未訓練的神經網絡,預測輸出顯然不會與實際期望結果相等。也因此,我們需要標注了正確結果的數據訓練神經網絡,使它能夠真正擬合數據集輸入與輸出間的映射關系。而這一訓練方式,我們稱為反向傳播(backpropagation)。最基礎的反向傳播訓練方法為梯度下降法(gradient descent),以此為基礎,為提高反向傳播訓練的收斂速度,又提出了帶動量的梯度下降法(gradient descent with momentum)等訓練方法;另外,在MatLab中,還提供包括Levenberg-Marquardt方法等的反向傳播算法。
 考慮具體的網格迷宮問題以及姿態控制問題,適用于圖像識別的卷積神經網絡(CNN)并不是我們所需要的。普通的前饋神經網絡模型即以足夠,MatLab除去可以使用feedforwardnet()函數構建前饋神經網絡外,還提供了函數擬合網絡fitnet()、模式識別網絡patternnet()兩種特殊的前饋神經網絡。
 對于網格迷宮問題,我們希望神經網絡模型能夠在以狀態-動作對為輸入的情況下輸出對應Q值。因此,可以調用fitnet()函數去擬合從狀態-動作對至Q函數值的映射關系。
二、fitnet()的調用與訓練
作為前饋神經網絡的一種特殊形式,fitnet()本質上與feedforwardnet()沒有太大差別。從MatLab語言上來說,兩者的調用、訓練、計算以及參數的調整也都是一致的。
 MatLab神經網絡工具箱對用戶非常友好,可以直接使用一行代碼完成前饋神經網絡的結構初始化:
%%構建指定層數及神經元數目的fitnet
QNet=fitnet([10,10,5]);     %行向量的元素數為神經網絡隱層的數目,每一個元素對應該層的神經元個數
同樣,構建好符合格式要求的訓練數據集后,MatLab也提供集成化的訓練函數train()進行神經網絡的訓練:
QNet=train(QNet,TrainsSet,TargetSet);
完成神經網絡的訓練后,我們即可以使用該神經網絡預測結果了:
Output=QNet(Input);
在訓練神經網絡和調用神經網絡進行計算時,MatLab提供了使用GPU進行計算的選項:
QNet=train(QNet,TrainsSet,TargetSet,’useGPU’,’yes’);
Output=QNet(Input,’useGPU’,’yes’);
對于普通個人電腦,直接調用GPU進行神經網絡運算的速度并不如使用CPU運算。因此,在之后的DQN實現中,我們也不會調用GPU進行運算。
另一個隨后要用到的,是神經網絡模型中一系列有關訓練的參數設置。MatLab中,train()函數本身并不定義反向傳播和迭代收斂的任何參數,而將這些參數保存在神經網絡對象中。在訓練過程中,train()函數訪問神經網絡對象中保存的訓練參數對神經網絡進行訓練。這樣,對于幾乎所有神經網絡,用戶都能在不主動調整train()參數情況下有針對性地對神經網絡進行訓練。fitnet()函數默認的反向傳播訓練算法為Levenberg-Marquardt方法;而DQN所需要的訓練算法則為梯度下降法,可以用如下的方式進行修改。而其它訓練參數的調用與修改也是類似的。
QNet.trainFcn=’traingdx’  %修改為自適應動量梯度下降法
三、練習:擬合二維曲面
具體的來說,我們用一個擬合二維曲面的問題來熟悉神經網絡這一對象的使用:
clear all;
%%構建指定層數及神經元數目的fitnet
QNet=fitnet([10,10,5]);     %行向量的元素數為神經網絡隱層的數目,每一個元素對應該層的神經元個數
%神經網絡初始化后,內部參數尚處于沒有訓練的過程,輸入層和輸出層元素的個數也沒有定義,可以通過訓練進行定義
%%訓練神經網絡
%使用標記好的數據集對QNet進行訓練。假設有k個樣本,神經網絡的輸入變量為m個,輸出變量為n個,則輸入數據的格式為m行*k列的矩陣,輸出數據為n行*k列的矩陣。
%我們在測試該網絡時,假設它有兩個自變量輸入以及一個輸出,因此如下生成訓練數據集。
%假設目標函數為如下形式:
[X1,Y1]=meshgrid(0.1:0.1:3,0.2:0.2:6);    %繪圖用橫縱坐標
target1=sin(1.5*sqrt(X1)+1*Y1);
x=0.1:0.1:3;
y=0.2:0.2:6;
%將上述結構轉換成符合神經網絡輸入、輸出的格式
Dataset=zeros(3,900);
for i=1:30
    for j=1:30
        Dataset(1,(i-1)*30+j)=x(i);
        Dataset(2,(i-1)*30+j)=y(j);
        Dataset(3,(i-1)*30+j)=target1(i,j);
    end
end
%抽取其中部分數據得到訓練數據集1
num1=200;
Trainset11=zeros(3,num1);
for i=1:num1
    Trainset11(:,i)=Dataset(:,unidrnd(900));
end
%訓練神經網絡
QNet=train(QNet,Trainset11(1:2,:),Trainset11(3,:));
%%使用神經網絡預測結果
%獲得訓練好的神經網絡后,我們即可以用該神經網絡根據輸入預測輸出
Input=Dataset(1:2,:);  %生成與目標數據集相同的輸入數據
Output1=QNet(Input);
Surf1=zeros(30,30);
for i=1:30
    for j=1:30
        Surf1(i,j)=Output1((i-1)*30+j);
    end
end
%%繪圖對比結果
%我們將神經網絡的預測輸出和實際函數值采用surf()函數進行可視化的對比
%彩色表面圖為真實輸出
surf(X1,Y1,target1,'FaceAlpha',0.5);
hold on;
%綠色表面圖為預測輸出
CO(:,:,1) = zeros(30); % red
CO(:,:,2) = ones(30).*linspace(0.2,0.8,30); % green
CO(:,:,3) = zeros(30); % blue
surf(X1,Y1,Surf1,CO,'FaceAlpha',0.7);
四、神經網絡的調用效率問題
在熟悉了神經網絡對象的一些基本使用方法后,我們最后來聊一聊神經網絡的調用效率問題。在傳統的Q學習中,我們需要在智能體進行一步學習時兩次Q表以獲得當前狀態-動作對以及下一狀態-動作對的Q值。將這一方法不變的遷移到神經網絡模型中,也就是說我們需要調用QNet()分別對兩組單獨的數據進行計算,在MatLab中,這樣的計算效率是非常低的。在上文訓練完成的神經網絡下,我們用下面的方式進行對比:
%代碼1
num2=400;
Input1=Dataset(1:2,1:num2);
Output1=QNet(Input1);
%代碼2
num2=400;
Input1=Dataset(1:2,1:num2);
Output1=zeros(1,num2);
for i=1:num2
    Output1(i)=QNet(Input(:,i));
End
使用運行并計時功能對比兩段代碼的用時:
 
 顯然,這兩段代碼實現了相同的功能,然而耗時卻明顯不同。代碼1用時約0.2s,代碼2用時卻超過4s。這是因為MatLab神經網絡對象中的內置函數net.Hints()及net.subserf()等函數的單次調用耗時較長的原因。
 也因此,在之后的編程中,為了提高程序的整體效率,高效調用神經網絡是必須要考慮的重點。
以上就是第三期我們要討論的全部內容,由于這一期并不涉及結構復雜的代碼,所以全部代碼均在文章中呈現。
十分歡迎各位讀者討論和打賞~
總結
以上是生活随笔為你收集整理的MATLAB强化学习入门——三、深度Q学习与神经网络工具箱(matlab入门图文教程)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: TSQL–标示列、GUID
 - 下一篇: how is webdynpro com