こんにちは.オーム社の「ロボットインテリジェンス」という本でC言語と強化学習を学び始めました.
その本の中の,迷路最適経路を求めるQ学習のサンプルプログラムを参考に自分で(5,7)から(5,1)まで1ステップずつ動く障害物を付け加えてみました.
きちんと動作しているのかを確かめるために,試行回数50回ごとに設定した迷路maze[x][y]とQ値Qtable[s][a]という二次元配列をexcelに出力しようと思ったのですが,上手くいきません.
無限ループに入ってしまったようです.
申し訳ありませんが,どのようにすればいいか教えてください.
よろしくお願いします.
長いですが以下,ソースコードです.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int move(int a, int &x, int &y, int x_size);
int xy2s(int x, int y, int x_size);
int select_action(int s, int num_a, double** Qtable);
double max_Qval(int s, int num_a, double** Qtable);
int epsilon_greedy(int epsilon, int s, int num_a, double** Qtable);
int k;
int main()
{
FILE *file;
file = fopen("Qtable.csv", "w");
int x_size;//x軸方向の迷路の大きさ(x_size=10の時には,xは0から9の値をとる) int y_size; double alpha, gamma;//α学習係数とγ減衰係数 int x, y, x_init, y_init; int **maze; int num_step;//一試行におけるQ値の更新回数 int num_trial;//試行回数 int i, j; int a, s, sd;//行動,状態,行動の実行によって遷移する状態 int num_a;//行動数 int num_s;//状態数 double **Qtable; int reward;//報酬 double Qmax;//Q値の最大値 int epsilon; //int k; //int u; //パラメータの設定 alpha = 0.5; gamma = 0.9; epsilon = 10; x_size = 10; y_size = 9; x_init = 1; y_init = 1; num_step = 500; num_trial = 55; num_a = 4;//行動の数 num_s = x_size*y_size;//状態の数 //乱数の初期化 srand((unsigned)time(NULL)); //Q-table Qtable = new double*[num_s]; for (i = 0; i < num_s; i++){ Qtable[i] = new double[num_a]; } //Q-tableの初期化 for (i = 0; i < num_s; i++){ for (j = 0; j < num_a; j++){ Qtable[i][j] = 0; } } //迷路 maze = new int*[x_size]; for (i = 0; i < x_size; i++){ maze[i] = new int[y_size]; } //迷路の初期化(迷路の周りに壁を設定) for (i = 0; i < x_size; i++){ for (j = 0; j < y_size; j++){ if (i == 0 || j == 0 || i == (x_size - 1) || j == (y_size - 1)){ maze[i][j] = -1; } else{ maze[i][j] = 0; } } } //壁の設定 maze[2][2] = -1; maze[3][2] = -1; maze[6][3] = -1; maze[7][3] = -1; maze[8][3] = -1; maze[2][6] = -1; maze[2][7] = -1; maze[3][6] = -1; maze[6][7] = -1; //報酬の設定 maze[8][6] = 10; //for (i = 0; i < x_size; i++){ // for (j = 0; j < y_size; j++){ // //printf("%3d", maze[i][j]);
// fprintf(file, "%3f" ,Qtable[i][j]);
// }
// printf("\n");
//}
//初期設定 x = x_init; y = y_init; s = xy2s(x, y, x_size); /******************************** * 試行開始 * ********************************/ //学習開始 for (i = 0; i < num_trial; i++){ for (j = 0; j < num_step; j++){ //Q値の更新の複数回更新 for(k = 7; 1 <= k ; --k){ maze[5][k]=-5; a = epsilon_greedy(epsilon, s, num_a, Qtable);//行動選択(ε-greedy法) sd = move(a, x, y, x_size);//エージェント移動 選択された行動に合わせてエージェントが移動,移動後の状態をsdに格納 reward = maze[x][y];//移動後の場所に設定している報酬をrewardに代入 Qmax = max_Qval(sd, num_a, Qtable);//遷移先の状態におけるQ値の最大値を求める Qtable[s][a] = Qtable[s][a] + alpha * ((double)reward + gamma * Qmax - Qtable[s][a]); //試行の成否の判断 //壁にぶつかったら"失敗"と表示して,エージェントを初期位置に戻して試行を終了,次の試行に移る //ゴールに到達した場合,"成功"と表示して,エージェントを初期位置に戻して試行を終了,次の試行に移る //どちらでもない場合,現在の状態に遷移先の状態を代入し,試行を継続する if (reward < 0){ //失敗 x = x_init; y = y_init; s = xy2s(x, y, x_size); maze[5][k]=0; goto OUT; } else if (reward > 0){ //成功 x = x_init; y = y_init; s = xy2s(x, y, x_size); maze[5][k]=0; goto OUT; } else{ //続行 s = sd; maze[5][k] = 0; goto OUT2; } }
OUT2:;
}
OUT:;
}
//政策の表示 for (x = 0; x<x_size; x++){ for (y = 0; y<y_size; y++){ s = xy2s(x, y, x_size); Qmax = max_Qval(s, num_a, Qtable); if (Qmax == 0){ printf("%3d", maze[x][y]); } else{ a = select_action(s, num_a, Qtable); if (a == 0){ printf(" →"); } else if (a == 1){ printf(" ↓"); } else if (a == 2){ printf(" ←"); } else{ printf(" ↑"); } } } printf("\n"); }
//ここでQtableの状態を出力したい
if (i=i+50){
for (x=0;x<x_size;x++){
for (y=0;y<y_size;y++){
for(a=0;a<4;a++){
s = x + y * x_size;
fprintf(file,"%f",Qtable[s][a]);
}
}
}
}
//ここまで
for (i = 0; i<num_s; i++){ delete[] Qtable[i]; } delete[] Qtable; for (i = 0; i<x_size; i++){ delete[] maze[i]; } delete[] maze; //ファイルクローズ fclose(file); return 0;
}
int move(int a, int &x, int &y, int x_size){
if (a == 0){ y = y + 1; } else if (a == 1){ x = x + 1; } else if (a == 2){ y = y - 1; } else{ x = x - 1; } int sd; sd = xy2s(x, y, x_size); return sd;
}
int xy2s(int x, int y, int x_size){
int s;
s = x + y * x_size;
return s;
}
/*************************
- 行動を選択する為の関数 *
**********************/
int select_action(int s, int num_a, double Qtable){//宣言(状態s,行動数num_a,Qtableで,Q値が最大になる行動を返す
double max;
int i = 0;
int i_max = new int[num_a];//最大値を持つQ値の行動を保存する為の変数
int num_i_max = 1;
int a;
i_max[0] = 0;//行動が0の時を初期値に max = Qtable[s][0]; //最大値の検索(大きなQ値が見つかると,新たな最大値として入力,num_i_maxを1に戻す) for (i = 1; i<num_a; i++){ if (Qtable[s][i]>max){ max = Qtable[s][i]; num_i_max = 1; i_max[0] = i; } else if (Qtable[s][i] == max){ num_i_max++; i_max[num_i_max - 1] = i; } } a = i_max[rand() % num_i_max];//最大値を持つ行動からランダムで1つを選択 return a;
}
//最大値を求める関数
double max_Qval(int s, int num_a, double** Qtable){
double max;
int i = 0;
max = Qtable[s][0];//Q[s][0]をmaxの初期値に設定 //maxとQの値を比較していく↓ for (i = 1; i<num_a; i++){ if (Qtable[s][i]>max){ max = Qtable[s][i];//もしQ > maxの時,maxにQを代入 } } return max;
}
//ε-greedy法の関数
int epsilon_greedy(int epsilon, int s, int num_a, double** Qtable){
int a;
if (epsilon > rand() % 100){
//無作為に行動を選択
a = rand() % num_a;
//printf("無作為に選択\n");
}
else{
//最大のQ値を持つ行動を選択
a = select_action(s, num_a, Qtable);
}
return a;
}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。