static void _Main(string[] args) { int success_num; double ITERATION = (3 * 10e5); double GAMMA = 0.95; CartPoleEnv env = new CartPoleEnv(WinFormEnvViewer.Factory); //or AvaloniaEnvViewer.Factory env.Seed(0); Space ob_space = env.ObservationSpace; Policy_net Policy = new Policy_net("policy", env); Policy_net Old_Policy = new Policy_net("old_policy", env); PPOTrain PPO = new PPOTrain(Policy, Old_Policy, gamma: GAMMA); Saver saver = tf.train.Saver(); using (var sess = tf.Session()) { writer = tf.summary.FileWriter("./log/test", sess.graph); sess.run(tf.global_variables_initializer()); saver.restore(sess, "model/model.ckpt"); obs = env.reset(); reward = 0; success_num = 0; for (double iteration = 0; iteration < ITERATION; iteration++) { // episode run_policy_steps = 0; env.render(); while (true) { // run policy RUN_POLICY_STEPS which is much less than episode length run_policy_steps += 1; obs = np.stack(new[] { obs }).astype(dtype: np.float32); // prepare to feed placeholder Policy.obs var(act, v_pred) = Policy.act(obs: obs, stochastic: false); act = act.item(); v_pred = v_pred.item(); observations.add(obs); actions.add(act); v_preds.add(v_pred); rewards.add(reward); var(next_obs, reward, done, info) = env.Step(act); if (done) { v_preds_next = v_preds[1 :] + [0]; // next state of terminate state has 0 state value
public PPOTrain(Policy_net policy, Policy_net old_policy, double gamma = 0.95, double clip_value = 0.2, double c_1 = 1, double c_2 = 0.01) { /* * :param Policy: * :param Old_Policy: * :param gamma: * :param clip_value: * :param c_1: parameter for value difference * :param c_2: parameter for entropy bonus */ Policy = policy; Old_Policy = old_policy; this.gamma = gamma; List <IVariableV1> pi_trainable = Policy.get_trainable_variables() as List <IVariableV1>; List <IVariableV1> old_pi_trainable = Old_Policy.get_trainable_variables(); // assign_operations for (policy parameter values to old policy parameters // atribuir operações para valores de parâmetros de política a parâmetros de política antigos using (tf.variable_scope("assign_op")) { foreach ((RefVariable v_old, Tensor v) in zip(old_pi_trainable, pi_trainable)) { this.assign_ops.Add(tf.assign(v_old, v)); } } // inputs for (train_op // inputs para train_op using (tf.variable_scope("train_inp")) { this.actions = tf.placeholder(dtype: tf.int32, shape: (Unknown), name: "actions"); this.rewards = tf.placeholder(dtype: tf.float32, shape: (Unknown), name: "rewards"); this.v_preds_next = tf.placeholder(dtype: tf.float32, shape: (Unknown), name: "v_preds_next"); this.gaes = tf.placeholder(dtype: tf.float32, shape: (Unknown), name: "gaes"); } Tensor act_probs = Policy.act_probs; Tensor act_probs_old = Old_Policy.act_probs; // probabilidades de ações que o agente executou com a política act_probs = act_probs * tf.one_hot(indices: this.actions, depth: act_probs.ToArray <double>().GetLength(1)); act_probs = tf.reduce_sum(act_probs, axis: 1); // probabilidades de ações que o agente executou com a política antiga act_probs_old = act_probs_old * tf.one_hot(indices: this.actions, depth: act_probs_old.ToArray <double>().GetLength(1)); act_probs_old = tf.reduce_sum(act_probs_old, axis: 1); using (tf.variable_scope("loss/clip")) { // ratios = tf.divide(act_probs, act_probs_old) Tensor ratios = tf.exp(tf.log(act_probs) - tf.log(act_probs_old)); Tensor clipped_ratios = tf.clip_by_value(ratios, clip_value_min: new Tensor(1 - clip_value), clip_value_max: new Tensor(1 + clip_value)); loss_clip = tf.minimum(tf.multiply(this.gaes, ratios), tf.multiply(this.gaes, clipped_ratios)); loss_clip = tf.reduce_mean(loss_clip); tf.summary.scalar("loss_clip", loss_clip); } // construct computation graph for (loss of value function // constrói gráfico de cálculo para perda da função de valor using (tf.variable_scope("loss/vf")) { Tensor v_preds = Policy.v_preds; loss_vf = tf.squared_difference(this.rewards + (gamma * this.v_preds_next), v_preds); loss_vf = tf.reduce_mean(loss_vf); tf.summary.scalar("loss_vf", loss_vf); } // construct computation graph for (loss of entropy bonus // construir gráfico de computação para perda de bônus de entropia using (tf.variable_scope("loss/entropy")) { entropy = -tf.reduce_sum(Policy.act_probs * tf.log(tf.clip_by_value(Policy.act_probs, new Tensor(1e-10), new Tensor(1.0))), axis: 1); entropy = tf.reduce_mean(entropy, axis: new[] { 0 }); // média de entropia de pi (obs) tf.summary.scalar("entropy", entropy); } using (tf.variable_scope("loss")) { loss = loss_clip - c_1 * loss_vf + c_2 * entropy; loss = -loss; // minimize -loss == maximize loss tf.summary.scalar("loss", loss); } this.merged = tf.summary.merge_all(); Optimizer optimizer = tf.train.AdamOptimizer(learning_rate: (float)1e-4, epsilon: (float)1e-5); this.train_op = optimizer.minimize(loss, var_list: pi_trainable); }
static void Main(string[] args) { List <NDArray> observations = new List <NDArray>(); List <NDArray> actions = new List <NDArray>(); List <NDArray> v_preds = new List <NDArray>(); List <double> rewards = new List <double>(); List <NDArray> v_preds_next = new List <NDArray>(); List <NDArray> gaes = new List <NDArray>(); double EPISODES = 1e5; double GAMMA = 0.95; CartPoleEnv env = new CartPoleEnv(WinFormEnvViewer.Factory); //or AvaloniaEnvViewer.Factory // Instancia o ambiente CartPole env.Seed(0); // Space ob_space = env.ObservationSpace; // Descrevem o formato de observações válidas do espaço Policy_net Policy = new Policy_net("policy", env); // Cria a rede de Politica Policy_net Old_Policy = new Policy_net("old_policy", env); // Cria a rede de politica antiga PPOTrain PPO = new PPOTrain(Policy, Old_Policy, gamma: GAMMA); Saver saver = tf.train.Saver(); // using (var sess = tf.Session()) // Bloco da sessão { FileWriter writer = tf.summary.FileWriter("./log/train", sess.graph); // Define diretório de logs sess.run(tf.global_variables_initializer()); // Inicializa as redes NDArray obs = env.Reset(); // Resets o ambiente e obtêm a primeira observação double reward = 0; // Armazena as recompensas int success_num = 0; // Contador de sucessos for (int episode = 0; episode < EPISODES; episode++) // Loop do episodio { int run_policy_steps = 0; // Contador de passos em cada episodio env.Render(); // Renderiza o ambiente while (true) // Execute a política RUN_POLICY_STEPS, que é muito menor que a duração do episódio { run_policy_steps += 1; // Incrementa contador de passos de cada episodio obs = np.stack(new[] { obs }).astype(dtype: np.float32); // prepare to feed placeholder Policy.obs (NDArray _act, NDArray _v_pred) = Policy.act(obs: obs, stochastic: true); // Corre a rede neural e obtêm uma ação e o V previsto int act = np.asscalar <int>(_act.ToArray <int>()); // Transforma um array do numpy NDArray v_pred = np.asscalar <double[]>(_v_pred.ToArray <double>()); // em um objeto scalar do Python //var v_pred = _v_pred.Item(); // em um objeto scalar do Python observations.Add(obs); // Adiciona a observação ao buffer de observações actions.Add(act); // Adiciona a ação ao buffer de ações v_preds.Add(v_pred); // Adiciona a v_pred ao buffer de v_pred rewards.Add(reward); // Adiciona a recompensa ao buffer de recompensa var(next_obs, _reward, done, _) = env.Step(act); // envia a ação ao ambiente e recebe a próxima observação, a recompensa e se o passo terminou reward = _reward; if (done) { // Se o done for (verdadeiro ... v_preds_next = v_preds; // [1:] seleciona do segundo elemento da lista em diante e + [0] adiciona um elemento de valor zero no final da lista v_preds_next.RemoveAt(0); v_preds_next.Add(0); // next state of terminate state has 0 state value // próximo estado do estado final tem 0 valor de estado obs = env.Reset(); // Redefine o ambiente reward = -1; // define a recompensa como -1 (?) break; // Sai do loop while } else { // Senão... obs = next_obs; // Armazena em obs a próxima observação } } // Armazena em log para visualização no tensorboard //writer.add_summary(tf.Summary(value:[tf.Summary.Value(tag:"episode_length", simple_value:run_policy_steps)]), episode); //writer.add_summary(tf.Summary(value:[tf.Summary.Value(tag:"episode_reward", simple_value:rewards.Sum())]), episode); // Condicional para finalizar o teste if (rewards.Sum() >= 195) { // Se a soma das recompensas for (maior ou igual 195 success_num += 1; // Incrementa o contador de sucessos if (success_num >= 100) { // Se ocorrerem 100 sucessos saver.save(sess, "./model/model.ckpt"); // Salva a sessão Console.WriteLine("Clear!! Model saved."); // Escreve na tela break; // Sai do loop } } else { // senão, success_num = 0; // zera o contador de sucessos } Console.WriteLine("EP: ", episode, " Rw: ", rewards.Sum()); // Escreve na tela o numero do episodio e a recompensa gaes = PPO.get_gaes(rewards: rewards, v_preds: v_preds, v_preds_next: v_preds_next); // ? // Converte lista em NPArray para alimentar o tf.placeholder //int[] newShape = ((-1), (list(ob_space.Shape)));// cria um array [-1, 4] var _observations = np.reshape(observations.ToArray(), shape: ((-1), (4)));// antes, cada linha de observations era um array independente. depois do reshape, observations passou ser um array só com varias linhas. var _actions = np.array(actions.ToArray(), dtype: np.int32); var _rewards = np.array(rewards.ToArray(), dtype: np.float32); var _v_preds_next = np.array(v_preds_next.ToArray(), dtype: np.float32); var __gaes = np.array(gaes.ToArray(), dtype: np.float32); var _gaes = (__gaes - __gaes.mean()) / __gaes.std(); // subtrai dos itens de gaes a media de todos os itens de gaes e divide todos pelo desvio padrão de gaes PPO.assign_policy_parameters(); NDArray[] inp = new[] { _observations, _actions, _rewards, _v_preds_next, _gaes }; // Cria um array com 5 colunas: observações, ações, recompensas, // Treina for (int epoch = 0; epoch < 4; epoch++) { NDArray sample_indices = np.random.randint(low: 0, high: observations.ToArray().GetLength(0), size: new Shape(64));// índices estão em [baixo, alto] var sampled_inp = new List <NDArray>(); foreach (NDArray arr in inp) { foreach (int indice in sample_indices.ToArray <int>()) { sampled_inp.Add(arr[0][indice]); } //sampled_inp.Add(np.Take(a: arr, índices: sample_indices, axis: 0)); // amostra de dados de treinamento } PPO.train(obs: sampled_inp[0], actions: sampled_inp[1], rewards: sampled_inp[2], v_preds_next: sampled_inp[3], gaes: sampled_inp[4]); } var summary = PPO.get_summary(obs: inp[0], actions: inp[1], rewards: inp[2], v_preds_next: inp[3], gaes: inp[4])[0]; //writer.add_summary(summary, episode); } //writer.close(); // Final do episódio } }