###前提・実現したいこと
強化学習(Q学習)でスタート地点からゴール地点までの最適な道のりを求めようとしています。
###発生している問題・エラーメッセージ
今、プログラムを50回回しても答えが出なかったら次の試行に行くようにしているのですが、次の試行に移った時にxy座標が更新されません。
また、ネットなどで調べてみると、最終的にQ学習は答えが収束すると書いてあったのですが、プログラムの試行回数を増やしても答えが収束しません。
この2つに悩んでいます。
お力を貸していただけると嬉しいです。
よろしくお願いします。
###ソースコード
C
1#define _CRT_SECURE_NO_WARNINGS 2#include <stdio.h> 3#include <stdlib.h> 4#include <time.h> 5#define _USE_MATH_DEFINES 6#include <math.h> 7 8typedef struct car { 9 double x; //現在位置x 10 double y; //現在位置y 11 double dx; //次の位置x 12 double dy; //次の位置y 13 double max_x; //xの最大値 14 double max_y; //yの最大値 15 int s; 16 int sd; 17 int L = 50; 18}agent; 19 20int move(car *agent, int a, int sd); 21int select_action(car *agent, int num_a, double** Qtable); 22double max_Qval(car *agent, int num_a, double** Qtable); 23int epsilon_greedy(car *agent, int epsilon, int num_a, double** Qtable); 24int xy2s(car *agent, int a); 25 26int main() { 27 FILE *file; 28 file = fopen("car.csv", "w"); 29 car agent; 30 31 int num_step; //ステップ数 32 int num_trial; //試行回数 33 int i, j; 34 int a; 35 double alpha, gamma; 36 37 int reward; //報酬 38 39 int num_a; //行動 40 int num_s; //状態 41 double **Qtable; 42 double Qmax; 43 int epsilon; 44 45 //パラメータの設定 46 alpha = 0.5; 47 gamma = 0.9; 48 epsilon = 10; 49 50 num_step = 50; 51 num_trial =500; 52 53 num_a = 4; 54 55 //エリアの数 56 num_s = 25; 57 int sepa = 5; 58 59 //乱数の初期化 60 srand((unsigned)time(NULL)); 61 62 //Q-table 63 Qtable = new double*[num_s]; 64 for (i = 0; i < num_s; i++) { 65 Qtable[i] = new double[num_a]; 66 } 67 68 //Q-tableの初期化 69 for (i = 0; i < num_s; i++) { 70 for (j = 0; j < num_a; j++) { 71 Qtable[i][j] = 0; 72 } 73 } 74 75 //agentの初期設定 76 agent.x = 25.0; 77 agent.y = 25.0; 78 agent.max_x = 250.0; 79 agent.max_y = 250.0; 80 81 agent.s = (int)agent.x / agent.L + (int)agent.y / agent.L * sepa; 82 83 //学習開始 84 for (i = 0; i < num_trial; i++) { 85 fprintf(file, "i=%d\n", i); 86 for (j = 0; j < num_step; j++) { 87 //fprintf(file, "j=%d\n", j); 88 flag: 89 a = epsilon_greedy(&agent, epsilon, num_a, Qtable);//どの方向に動くか決める 90 agent.s = (int)agent.x / agent.L + (int)agent.y / agent.L * sepa;//現在のarea 91 92 agent.sd = move(&agent, a, agent.s); 93 printf("%f,%f\n", agent.x, agent.y); 94 95 //ここで障害物の設定 96 //障害物があるagent.sに入るとrewardに-10が入り試行を終了する 97 //Goalに入るとrewardに+10が入り試行を終了 98 //その他はreward=0なのでそのまま続行 99 100 if (agent.s == 20) { 101 reward = 1000; 102 } 103 else if(agent.s == 15) { 104 reward = -10; 105 } 106 else { 107 reward = 0; 108 } 109 if (agent.dx < 0 || agent.dx > agent.max_x || agent.dy < 0 || agent.dy > agent.max_y) { 110 goto flag; 111 } 112 113 Qmax = max_Qval(&agent, num_a, Qtable); 114 Qtable[agent.s][a] = (1 - alpha)*Qtable[agent.s][a] + alpha * ((double)reward + gamma*Qmax);//?? 115 116 fprintf(file, "%f,%f,a=%d,s=%d,sd=%d,%d\n", agent.x, agent.y, a, agent.s, agent.sd,reward); 117 118 if (reward < 0) { 119 //失敗 120 agent.x = 25.0; 121 agent.y = 25.0; 122 agent.s = (int)agent.x / agent.L + (int)agent.y / agent.L * sepa; 123 break; 124 } 125 else if (reward > 0) { 126 //成功 127 agent.x = 25.0; 128 agent.y = 25.0; 129 agent.s = (int)agent.x / agent.L + (int)agent.y / agent.L * sepa; 130 break; 131 } 132 else { 133 //続行 134 agent.x = agent.dx; 135 agent.y = agent.dy; 136 agent.s = agent.sd; 137 } 138 } 139 } 140 141 fclose(file); 142 return 0; 143} 144 145int move(car *agent, int a, int sd) { 146 147 switch (a) { 148 case 0://↑ 149 agent->dy = agent->y + 50.0; 150 agent->dx = agent->x; 151 break; 152 case 1://→ 153 agent->dx = agent->x + 50.0; 154 agent->dy = agent->y; 155 break; 156 case 2://↓ 157 agent->dy = agent->y - 50.0; 158 agent->dx = agent->x; 159 break; 160 case 3://← 161 agent->dx = agent->x - 50.0; 162 agent->dy = agent->y; 163 break; 164 } 165 //sdはアクションが起こった後のagent.sを表す 166 agent->sd = (int)agent->dx / agent->L + (int)agent->dy / agent->L * 5; 167 return agent->sd; 168} 169 170 171int select_action(car *agent, int num_a, double**Qtable) { 172 double max; 173 int i = 0; 174 int* i_max = new int[num_a]; 175 int num_i_max = 1; 176 int a; 177 i_max[0] = 0; 178 max = Qtable[agent->s][0]; 179 180 for (i = 0; i < num_a; i++) { 181 if (Qtable[agent->s][i] > max) { 182 num_i_max = 1; 183 i_max[0] = i; 184 } 185 else if (Qtable[agent->s][i] == max) { 186 num_i_max++; 187 i_max[num_i_max - 1] = i; 188 } 189 } 190 191 a = i_max[rand() % num_i_max]; 192 return a; 193} 194 195double max_Qval(car *agent, int num_a, double** Qtable) { 196 double max; 197 int i = 0; 198 199 max = Qtable[agent->s][0];//? 200 for (i = 0; i < num_a; i++) {//1? 201 if (Qtable[agent->s][i] > max) { 202 max = Qtable[agent->s][i]; 203 } 204 } 205 return max; 206} 207 208int epsilon_greedy(car *agent, int epsilon, int num_a, double** Qtable) { 209 int a; 210 if (epsilon > rand() % 100) { 211 a = rand() % num_a; 212 } 213 else { 214 a = select_action(agent, num_a, Qtable); 215 } 216 return a; 217}
###補足情報(言語/FW/ツール等のバージョンなど)
typedef で agent にしてるのに car 型で定義してしかも変数名が agent なのはなぜ?
すみません。初心者なものでネットで調べたものを使いました。
少し見づらくてすみません。
typedef struct employee {
char name\\\[12\\\];
double hours;
int wage;
} EMPLOYEE;
EMPLOYEE yamada; // EMPLOYEE 型の変数 yamada を作成
その例では、
① struct employee 型を typedef によって EMPLOYEE として使えるようにしている(別名)
②EMPLOYEE 型の変数 yamada を定義
Cでは本来 struct employee yamada と、構造体変数の宣言時は頭に struct を付けなければならないのを、「EMPLOYEE」=「struct employee」として簡単に書けるようにしているのです。
たいして質問者さんのコードでは、car で変数型を宣言している(C++でなら許されるんじゃないかな?)、typedef で別名に指定した agent を変数名にしているのでわかりづらいコードになってしまっているように思います。
一度 typedef を調べてみてはいかがでしょうか