人工智能-實驗一策略迭代和值迭代


1.實驗問題

在4x4矩陣中添加終點和障礙點,分別有一個或多個,並且滿足以下屬性:

        終點:value值不變,始終為0,鄰接點可到達用大寫字母E表示

        障礙點:表示該點在矩陣中“不存在”,鄰接點不可到達該點,且該點沒有value值跟狀態,使用符號‘#’表示

  以任意除以上兩種結點之外的所有其它結點為起點,求解起點到終點的最短距離,存在多終點時,以相隔最近的終結點為准。

 

2.實驗思路

1)  使用值Policy Iteration和Value Iteration算法分別計算問題產生的最佳策略

2)  設置獎勵值r=-1,折扣值disc = 0.57f,使用新舊兩個狀態矩陣和兩個Value矩陣用於迭代過程中保存狀態變化和價值變化。

3) MDP模型描述:

      S: 狀態集合為{0…15},由4x4的矩陣S存儲,狀態與狀態之間滿足馬爾可夫屬性,因為當前狀態可到達的狀態最多四個,后繼狀態只受當前狀態影響。

      A:可采取的action集合,使用A={n,e,s,w},北東南西表示

      P:狀態轉移概率矩陣:不在編程中顯式出現,因為迭代時已知繼承狀態的value值

      R : 因為求解最短距離,agent每行動一步可獲的獎勵為r=-1

      γ : 折扣因子設置為 0.57,在0~1之間可調,但不能等於0或1,否則會造成無法收斂,無限循環的問題。

4) 值迭代:

       a.初始化每個狀態的value值為V(s) = 0;

       b.然后最大化每個狀態當前的value值,包括行動獎勵和未來獎勵,直到value值變化不明顯為止

       c.根據以上步驟求得的收斂值矩陣V,對每個狀態遍歷查找使得總獎勵(行動獎勵和未來獎勵)最大的action,放入策略矩陣S,並打印輸出。

 

5)策略迭代:

       a.初始化V矩陣為0,狀態矩陣中的每個狀態隨機選擇四個方向之一進行初始化,並且在狀態矩陣中添加障礙點’#’和終結點‘E’

       b.根據選擇的策略,最優化V矩陣

       c.優化當前策略:如果當前策略並不使得當前狀態的value值最大,那么把當前策略替換為最優策略

       d如果對於所有狀態,所有策略均未發生改變,那么輸出當前的最佳策略,否則繼續從b開始循環

 

3.實驗結果

 

  1)策略迭代

    不同障礙及不同終節點下的收斂情況,其中 ‘#’表示障礙,‘E’表示終結點


 

 

2 )值迭代

      不同障礙和終結點,折扣值為1.0

        

          

4.實驗代碼;

   1)策略迭代:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <set>
#include <queue>
#include <windows.h>  
#include <string>

using namespace std;

const int MAX_N = 4;
const float INF = -999999999.0f;
float V[MAX_N][MAX_N];      //值矩陣
float OLDV[MAX_N][MAX_N];    //保存舊的val值
char S[MAX_N][MAX_N];      //狀態矩陣,直觀存儲運動方向
char OLDS[MAX_N][MAX_N];   //舊的狀態矩陣
char A[4] = { 'n','e','s','w' };     //Action ,'↑','→','↓','←'
int dx[] = { -1,0,1,0 }, dy[]= { 0,1,0,-1 };  //四向移動
int r = -1;                  //獎勵值
float disc = 0.57f;            //折扣值
float en = 0.00000001f;        //sub小於這個數時收斂


//  獲取輸出流的句柄
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

//初始化
void init() {
    for (int i = 0; i < MAX_N; i++)
        for (int j = 0; j < MAX_N; j++) {
            S[i][j] = 'n';                    //初始化為向右走
            OLDS[i][j] = 'n';
        }
    OLDS[0][0] = S[0][0] = '#';                       
      OLDS[3][3] = S[3][3] = 'E';                       //目標點    
      

      OLDS[2][2] = S[2][2] = 'E';      //障礙
      OLDS[2][1] = S[2][1] = '#';
      OLDS[2][3] = S[2][3] = '#';

}

int getIndex(char ch) {
    switch (ch) {
    case 'n':
        return 0;
    case 'e':
        return 1;
    case 's':
        return 2;
    case 'w':
        return 3;
    default:
        return -1;
    }
}

void printVal() {
    puts("----------------value-----------------");
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            printf("%f ", V[i][j]);
        }
        puts("\n");
    }
}
void printState() {
    puts("----------------State-----------------");
    //打印策略
    for (int i = 0; i < MAX_N; i++) {
        printf("        ");
        for (int j = 0; j < MAX_N; j++) {
            switch (S[i][j]) {
            case 'n':
                printf("");
                break;
            case 'e':
                printf("");
                break;
            case 's':
                printf("");
                break;
            case 'w':
                printf("");
                break;
            default:
                printf("%c   ", S[i][j]);
                break;
            }
        }
        puts("\n");
    }
}

void PolicyEvaluation(){
    float sub;
    int cnt = 0;
    do{
        sub = 0.0f;
        for (int i = 0; i < MAX_N; i++) {
            for (int j = 0; j < MAX_N; j++) {

                if (S[i][j] != '#' && S[i][j] != 'E') {           //不是障礙物及終點
                    float val = V[i][j];
                    int k = getIndex(S[i][j]);       //根據狀態得出移動下標
                    int x = i + dx[k], y = j + dy[k];
                    if (x >= 0 && x < MAX_N && y >= 0 && y < MAX_N && S[x][y] != '#') {
                        V[i][j] = r +  disc * OLDV[x][y];
                    }
                    sub = max(sub, fabs(val - V[i][j]));
                }
            }
       }

        //把新的val值拷貝到舊的數組中
        for (int i = 0; i < MAX_N; i++) {
            for (int j = 0; j < MAX_N; j++) {
                OLDV[i][j] = V[i][j];
            }
        }

        printf("cnt :   %d\n", ++cnt);
        printVal();
            
    } while (sub > en);
}

void PolicyImprovement() {

  while (true) {

    bool stable = true;
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            if (OLDS[i][j] != '#' && OLDS[i][j] != 'E') {
                char oldact = OLDS[i][j];
                int k = 4;
                float ma = INF;
                while (k--) {
                    int x = i + dx[k], y = j + dy[k];
                    if (x >= 0 && x < MAX_N && y >= 0 && y < MAX_N && OLDS[x][y] != '#') {
                        float round = r + disc * OLDV[x][y];
                        if (round - ma > en) {
                            ma = round;    //改變Val值
                            S[i][j] = A[k];    //改變當前狀態的最佳策略
                            char ch = A[k];
                        }
                    }
                }

                if (oldact != S[i][j])
                    stable = false;
            }
        }
    }

    //將所有新狀態拷貝至舊狀態
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            OLDS[i][j] = S[i][j];
        }
    }
        
    if (stable) {
       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
       printf("\n--------------------------STOP-----------------------\n");

       printVal();
       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0xA); //亮綠
       printState();
       break;
     }
     else {
        PolicyEvaluation();    //繼續策略迭代
     }
   }
}


int main() {

    init();
    PolicyEvaluation();
    PolicyImprovement();
    return 0;
}

2)值迭代

   

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <Windows.h>

using namespace std;

const int MAX_N = 4;
const float INF = -999999999.0f;
float V[MAX_N][MAX_N];      //值矩陣
float OLDV[MAX_N][MAX_N];    //保存舊的val值
char S[MAX_N][MAX_N];      //狀態矩陣,直觀存儲運動方向
                           //float P[MAX_N*MAX_N][MAX_N*MAX_N];    //狀態轉移概率矩陣
char A[4] = { 'n','e','s','w' };     //Action ,'↑','→','↓','←'
int dx[] = { -1,0,1,0 }, dy[] = { 0,1,0,-1 };  //四向移動
int r = -1;                  //獎勵值
float disc = 1.0f;            //折扣值
float en = 0.0000001f;        //sub小於這個數時收斂

 //初始化                              
void init() {
    for (int i = 0; i < MAX_N; i++)
        for (int j = 0; j < MAX_N; j++) {
            S[i][j] = 'w';                    //初始化為向右走
        }
    S[0][2] = '#';                       //#障礙
    S[3][1] = 'E';                       //E目標點            
    S[2][2] = '#';
    S[1][2] = 'E';
    S[1][2] = '#';
}


int getIndex(char ch) {
    switch (ch) {
    case 'n':
        return 0;
    case 'e':
        return 1;
    case 's':
        return 2;
    case 'w':
        return 3;
    default:
        return -1;
    }
}

void printVal() {
    puts("----------------value-----------------");
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            printf("%.4f ", V[i][j]);
        }
        puts("\n");
    }
}

void ValueIteration() {
    float sub = 0;
    int cnt = 0;
    do {
        sub = 0;
        for (int i = 0; i < MAX_N; i++) {
            for (int j = 0; j < MAX_N; j++) {
                if (S[i][j] != '#' && S[i][j] != 'E') {           //不是障礙物及終點
                    float val = V[i][j];
                    int k = 4;
                    int ma = INF;
                    while (k--) {
                        int x = i + dx[k], y = j + dy[k];
                        if (x >= 0 && x < MAX_N && y >= 0 && y < MAX_N && S[x][y] != '#') {
                            float round = r + disc * OLDV[x][y];
                            if (ma < round) {
                                 ma = round;    //改變Val值
                            }
                        }
                    }
                    if (ma != INF)
                        V[i][j] = ma;                        //V[i][j]取得周圍環境的最大值

                    sub = max(sub, fabs(val - V[i][j]));
                }
            }
        }

        //把新的val值拷貝到舊的數組中
        for (int i = 0; i < MAX_N; i++) {
            for (int j = 0; j < MAX_N; j++) {
                OLDV[i][j] = V[i][j];
            }
        }
        printf("cnt :   %d\n", ++cnt);
        printVal();

    } while (sub >= en);


    //更新最佳策略
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            if (S[i][j] != '#' && S[i][j] != 'E') {           //不是障礙物及終點
                int k = 4;
                int ma = INF;
                while (k--) {
                    int x = i + dx[k], y = j + dy[k];
                    if (x >= 0 && x < MAX_N && y >= 0 && y < MAX_N && S[x][y] != '#') {
                        float round = r + disc * OLDV[x][y];
                        if (ma < round) {
                            ma = round;    //改變Val值
                            S[i][j] = A[k];
                        }
                    }
                }
            }
        }
    }

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0xA); //亮綠
    //打印策略
    for (int i = 0; i < MAX_N; i++) {
        for (int j = 0; j < MAX_N; j++) {
            char ch;
            switch (S[i][j]) {
              case 'n':
                  printf("");
                  break;
              case 'e':
                  printf("");
                  break;
              case 's':
                  printf("");
                  break;
              case 'w':
                  printf("");
                  break;
              default:
                  printf("%c ", S[i][j]);
                  break;
            }
        }
        puts("\n");
    }

}


int main() {

    init();
    ValueIteration();
    return 0;
}

 

 

 

     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM