正如在前面所提到的,強化學習是指一種計算機以「試錯」的方式進行學習,經過與環境進行交互得到的獎賞指導行爲,目標是使程序得到最大的獎賞,強化學習不一樣於連督學習,區別主要表如今強化信號上,強化學習中由環境提供的強化信號是對產生動做的好壞做一種評價(一般爲標量信號),而不是告訴強化學習系統如何去產生正確的動做。惟一的目的是最大化效率和/或性能。算法對正確的決策給予獎勵,對錯誤的決策給予懲罰,以下圖所示:html
持續的訓練是爲了避免斷提升效率。這裏的重點是性能,這意味着咱們須要,在看不見的數據和算法已經學過的東西,之間找到一種平衡。該算法將一個操做應用到它的環境中,根據它所作的行爲接受獎勵或懲罰,不斷的重複這個過程,等等。算法
接下來讓咱們看一個程序,概念是類似的,儘管它的規模和複雜性很低。想象一下,是什麼讓自動駕駛的車輛從一個地點移動到了另外一個點。數組
讓咱們看看咱們的應用程序:dom
在這裏,能夠看到咱們有一個很是基本的地圖,一個沒有障礙,但有外部限制的牆。黑色塊(start)是咱們的對象,紅色塊(stop)是咱們的目標。在這個應用程序中,咱們的目標是讓咱們的對象在牆壁之內到達目標位置。若是咱們的下一步把咱們的對象放在一個白色的方塊上,咱們的算法將獲得獎勵。若是咱們的下一步行動超出牆壁的圍地範圍,咱們將受到懲罰。在這個例子中,它的路徑上絕對沒有障礙,因此咱們的對象應該可以到達它的目的地。問題是:它能多快學會?
下面是另外一個比較複雜的地圖示例:性能
在應用程序的右邊是咱們的設置,以下面的屏幕截圖所示。咱們首先看到的是學習算法。在這個應用中,咱們將處理兩種不一樣的學習算法,Q-learning和state-action-reward-state-action (SARSA)。讓咱們簡要討論一下這兩種算法。學習
Q-learning能夠在沒有徹底定義的環境模型的狀況下,識別給定狀態下的最優行爲(在每一個狀態中值最高的行爲)。它還擅長處理隨機轉換和獎勵的問題,而不須要調整或適應。動畫
如下是Q-learning的數學表達式:spa
若是咱們提供一個很是高級的抽象示例,可能更容易理解。線程
程序從狀態1開始。而後它執行動做1並得到獎勵1。接下來,它四處尋找狀態2中某個行爲的最大可能獎勵是多少;而後使用它來更新動做1的值等等。3d
SARSA
SARSA的工做原理是這樣的:
1. 程序從狀態1開始。
2. 而後它執行動做1並得到獎勵1。
3. 接下來,它進入狀態2,執行動做2,並得到獎勵2。
4. 而後,程序返回並更新動做1的值。
這Q-learning算法的不一樣之處在於找到將來獎勵的方式。
Q-learning使用狀態2中獎勵最高的動做的值,而SARSA使用實際動做的值。
這是SARSA的數學表達式:
運行咱們的應用程序
如今,讓咱們開始使用帶有默認參數的應用程序。只需點擊開始按鈕,學習就開始了。完成後,您將可以單擊Show Solution按鈕,學習路徑將從頭至尾播放。
點擊Start開始學習階段,一直到黑色物體達到目標:
對於每一個迭代,將評估不一樣的對象位置,以及它們的操做和獎勵。一旦學習完成,咱們能夠單擊Show Solution按鈕來重播最終的解決方案。完成後,黑色對象將位於紅色對象之上:
如今讓咱們看看應用程序中的代碼。有兩種咱們以前強調過的學習方法。
Q-learning是這樣的:
/// <summary> /// Q-Learning 線程 /// </summary> private void QLearningThread() { //迭代次數 int iteration = 0; TabuSearchExploration tabuPolicy = (TabuSearchExploration)qLearning.ExplorationPolicy; EpsilonGreedyExploration explorationPolicy = (EpsilonGreedyExploration)tabuPolicy.BasePolicy; while ((!needToStop)&&(iteration<learningIterations)) { explorationPolicy.Epsilon = explorationRate - ((double)iteration / learningIterations) * explorationRate; qLearning.LearningRate = learningRate - ((double)iteration / learningIterations) * learningRate; tabuPolicy.ResetTabuList(); var agentCurrentX = agentStartX; var agentCurrentY = agentStartY; int steps = 0; while ((!needToStop)&& ((agentCurrentX != agentStopX) || (agentCurrentY != agentStopY))) { steps++; int currentState= GetStateNumber(agentCurrentX, agentCurrentY); int action = qLearning.GetAction(currentState); double reward = UpdateAgentPosition(ref agentCurrentX, ref agentCurrentY, action); int nextState = GetStateNumber(agentCurrentX, agentCurrentY); // 更新對象的qLearning以設置禁忌行爲 qLearning.UpdateState(currentState, action, reward, nextState); tabuPolicy.SetTabuAction((action + 2) % 4, 1); } System.Diagnostics.Debug.WriteLine(steps); iteration++; SetText(iterationBox, iteration.ToString()); } EnableControls(true); }
SARSA學習有何不一樣?讓咱們來看看SARSA學習的while循環,並理解它:
/// <summary> /// Sarsa 學習線程 /// </summary> private void SarsaThread() { int iteration = 0; TabuSearchExploration tabuPolicy = (TabuSearchExploration)sarsa.ExplorationPolicy; EpsilonGreedyExploration explorationPolicy = (EpsilonGreedyExploration)tabuPolicy.BasePolicy; while ((!needToStop) && (iteration < learningIterations)) { explorationPolicy.Epsilon = explorationRate - ((double)iteration / learningIterations) * explorationRate; sarsa.LearningRate = learningRate - ((double)iteration / learningIterations) * learningRate; tabuPolicy.ResetTabuList(); var agentCurrentX = agentStartX; var agentCurrentY = agentStartY; int steps = 1; int previousState = GetStateNumber(agentCurrentX, agentCurrentY); int previousAction = sarsa.GetAction(previousState); double reward = UpdateAgentPosition(ref agentCurrentX, ref agentCurrentY, previousAction); while ((!needToStop) && ((agentCurrentX != agentStopX) || (agentCurrentY != agentStopY))) { steps++; tabuPolicy.SetTabuAction((previousAction + 2) % 4, 1); int nextState = GetStateNumber(agentCurrentX, agentCurrentY); int nextAction = sarsa.GetAction(nextState); sarsa.UpdateState(previousState, previousAction, reward, nextState, nextAction); reward = UpdateAgentPosition(ref agentCurrentX, ref agentCurrentY, nextAction); previousState = nextState; previousAction = nextAction; } if (!needToStop) { sarsa.UpdateState(previousState, previousAction, reward); } System.Diagnostics.Debug.WriteLine(steps); iteration++; SetText(iterationBox, iteration.ToString()); } // 啓用設置控件 EnableControls(true); }
最後一步,看看如何使解決方案具備動畫效果。咱們須要這樣才能看到咱們的算法是否實現了它的目標。
代碼以下:
TabuSearchExploration tabuPolicy; if (qLearning != null) tabuPolicy = (TabuSearchExploration)qLearning.ExplorationPolicy; else if (sarsa != null) tabuPolicy = (TabuSearchExploration)sarsa.ExplorationPolicy; else throw new Exception(); var explorationPolicy = (EpsilonGreedyExploration)tabuPolicy?.BasePolicy; explorationPolicy.Epsilon = 0; tabuPolicy?.ResetTabuList(); int agentCurrentX = agentStartX, agentCurrentY = agentStartY; Array.Copy(map, mapToDisplay, mapWidth * mapHeight); mapToDisplay[agentStartY, agentStartX] = 2; mapToDisplay[agentStopY, agentStopX] = 3;
這是咱們的while循環,全部神奇的事情都發生在這裏!
while (!needToStop) { cellWorld.Map = mapToDisplay; Thread.Sleep(200); if ((agentCurrentX == agentStopX) && (agentCurrentY == agentStopY)) { mapToDisplay[agentStartY, agentStartX] = 2; mapToDisplay[agentStopY, agentStopX] = 3; agentCurrentX = agentStartX; agentCurrentY = agentStartY; cellWorld.Map = mapToDisplay; Thread.Sleep(200); } mapToDisplay[agentCurrentY, agentCurrentX] = 0; int currentState = GetStateNumber(agentCurrentX, agentCurrentY); int action = qLearning?.GetAction(currentState) ?? sarsa.GetAction(currentState); UpdateAgentPosition(ref agentCurrentX, ref agentCurrentY, action); mapToDisplay[agentCurrentY, agentCurrentX] = 2; }
讓咱們把它分紅更容易消化的部分。咱們要作的第一件事就是創建禁忌政策。若是您不熟悉tabu搜索,請注意,它的目的是經過放鬆其規則來提升本地搜索的性能。在每一步中,若是沒有其餘選擇(有回報的行動),有時惡化行動是能夠接受的。
此外,還設置了prohibition (tabu),以確保算法不會返回到之前訪問的解決方案。
TabuSearchExploration tabuPolicy; if (qLearning != null) tabuPolicy = (TabuSearchExploration)qLearning.ExplorationPolicy; else if (sarsa != null) tabuPolicy = (TabuSearchExploration)sarsa.ExplorationPolicy; else throw new Exception(); var explorationPolicy = (EpsilonGreedyExploration)tabuPolicy?.BasePolicy; explorationPolicy.Epsilon = 0; tabuPolicy?.ResetTabuList();
接下來,咱們要定位咱們的對象並準備地圖。
int agentCurrentX = agentStartX, agentCurrentY = agentStartY; Array.Copy(map, mapToDisplay, mapWidth * mapHeight); mapToDisplay[agentStartY, agentStartX] = 2; mapToDisplay[agentStopY, agentStopX] = 3;
下面是咱們的主執行循環,它將以動畫的方式顯示解決方案:
while (!needToStop) { cellWorld.Map = mapToDisplay; Thread.Sleep(200); if ((agentCurrentX == agentStopX) && (agentCurrentY == agentStopY)) { mapToDisplay[agentStartY, agentStartX] = 2; mapToDisplay[agentStopY, agentStopX] = 3; agentCurrentX = agentStartX; agentCurrentY = agentStartY; cellWorld.Map = mapToDisplay; Thread.Sleep(200); } mapToDisplay[agentCurrentY, agentCurrentX] = 0; int currentState = GetStateNumber(agentCurrentX, agentCurrentY); int action = qLearning?.GetAction(currentState) ?? sarsa.GetAction(currentState); UpdateAgentPosition(ref agentCurrentX, ref agentCurrentY, action); mapToDisplay[agentCurrentY, agentCurrentX] = 2; }
河內塔由三根杆子和最左邊的幾個按順序大小排列的圓盤組成。目標是用最少的移動次數將全部磁盤從最左邊的棒子移動到最右邊的棒子。
你必須遵照的兩條重要規則是,一次只能移動一個磁盤,不能把大磁盤放在小磁盤上;也就是說,在任何棒中,磁盤的順序必須始終是從底部最大的磁盤到頂部最小的磁盤,以下所示:
假設咱們使用三個磁盤,如圖所示。在這種狀況下,有33種可能的狀態,以下圖所示:
河內塔謎題中全部可能狀態的總數是3的磁盤數次冪。
其中||S||是集合狀態中的元素個數,n是磁盤的個數。
在咱們的例子中,咱們有3×3×3 = 27個圓盤在這三根棒上分佈的惟一可能狀態,包括空棒;可是兩個空棒能夠處於最大狀態。
定義了狀態總數以後,下面是咱們的算法從一種狀態移動到另外一種狀態的全部可能操做:
這個謎題的最小可能步數是:
磁盤的數量是n。
Q-learning算法的正式定義以下:
在這個Q-learning算法中,咱們使用瞭如下變量:
咱們應該簡要介紹一下Q-learning Class的一些方法:
Init:生成全部可能的狀態以及開始學習過程。
Learn:在學習過程當中有順序的步驟
InitRMatrix: 這個初始化獎勵矩陣的值以下:
1. 0:在這種狀態下,咱們沒有獎勵。
2. 100:這是咱們在最終狀態下的最大獎勵,咱們想去的地方。
3. X:在這種狀況下是不可能採起這種行動的。
TrainQMatrix: 包含Q矩陣的實際迭代值更新規則。完成後,咱們但願獲得一個訓練有素的對象。
NormalizeQMatrix: 使Q矩陣的值標準化,使它們成爲百分數。
Test: 提供來自用戶的文本輸入,並顯示解決此難題的最佳最短路徑。
讓咱們更深刻地研究咱們的TrainQMatrix的代碼:
/// <summary> /// 訓練Q矩陣 /// </summary> /// <param name="_StatesMaxCount">全部可能移動的個數</param> private void TrainQMatrix(int _StatesMaxCount) { pickedActions = new Dictionary<int, int>(); // 可用操做列表(基於R矩陣,其中包含從某個狀態開始的容許的下一個操做,在數組中爲0) List<int> nextActions = new List<int>(); int counter = 0; int rIndex = 0; // 3乘以全部可能移動的個數就有足夠的集來訓練Q矩陣 while (counter < 3 * _StatesMaxCount) { var init = Utility.GetRandomNumber(0, _StatesMaxCount); do { // 得到可用的動做 nextActions = GetNextActions(_StatesMaxCount, init); // 從可用動做中隨機選擇一個動做 if (nextActions != null) { var nextStep = Utility.GetRandomNumber(0, nextActions.Count); nextStep = nextActions[nextStep]; // 得到可用的動做 nextActions = GetNextActions(_StatesMaxCount, nextStep); // 設置從該狀態採起的動做的索引 for (int i = 0; i < 3; i++) { if (R != null && R[init, i, 1] == nextStep) rIndex = i; } // 這是值迭代更新規則-折現係數是0.8 Q[init, nextStep] = R[init, rIndex, 0] + 0.8 * Utility.GetMax(Q, nextStep, nextActions); // 將下一步設置爲當前步驟 init = nextStep; } } while (init != FinalStateIndex); counter++; } }
使用三個磁盤運行應用程序:
使用四個磁盤運行應用程序:
這裏有7個磁盤。最佳移動步數是127,因此你能夠看到解決方案能夠多快地乘以可能的組合:
這種形式的強化學習更正式地稱爲馬爾可夫決策過程(Markov Decision Process, MDP)。MDP是一個離散時間隨機控制的過程,這意味着在每一個時間步,在狀態x下,決策者能夠選擇任何可用的行動狀態,這個過程將在下一步反應,隨機移動到一個新的狀態,給決策者一個獎勵。進程進入新狀態的機率由所選動做決定。所以,下一個狀態取決於當前狀態和決策者的行爲。給定狀態和操做,下一步徹底獨立於以前的全部狀態和操做。