Skip to content

Instantly share code, notes, and snippets.

@jskDr
Created September 29, 2019 13:36
Show Gist options
  • Save jskDr/9b9d7ce98d25632a0b1d5184bdbafc7c to your computer and use it in GitHub Desktop.
Save jskDr/9b9d7ce98d25632a0b1d5184bdbafc7c to your computer and use it in GitHub Desktop.
Policy Gradient with PyTorch and Python Class Structure
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"# Using ipython\n",
"from IPython.display import clear_output\n",
"\n",
"import gym\n",
"import random\n",
"from itertools import count\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Using torch\n",
"import torch as TC\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"from torch.autograd import Variable\n",
"from torch.distributions import Bernoulli"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def list_norm_inplace(buff):\n",
" r_mean = np.mean(buff)\n",
" r_std = np.std(buff)\n",
" for ii in range(len(buff)):\n",
" buff[ii] = (buff[ii] - r_mean) / r_std\n",
"\n",
" \n",
"def plot_durations(episode_durations):\n",
" plt.figure(2)\n",
" plt.clf()\n",
" durations_t = TC.FloatTensor(episode_durations)\n",
" plt.title('Training...')\n",
" plt.xlabel('Episode')\n",
" plt.ylabel('Duration')\n",
" plt.plot(durations_t.numpy())\n",
" # Take 100 episode averages and plot them too\n",
" if len(durations_t) >= 100:\n",
" means = durations_t.unfold(0, 100, 1).mean(1).view(-1)\n",
" means = TC.cat((TC.zeros(99), means))\n",
" plt.plot(means.numpy())\n",
" plt.show()\n",
" \n",
" \n",
"def plot_durations_ii(ii, episode_durations, ee, ee_duration=100):\n",
" episode_durations.append(ii+1)\n",
" if (ee + 1) % ee_duration == 0:\n",
" clear_output()\n",
" plot_durations(episode_durations)\n",
" \n",
" \n",
"class PGNET(nn.Module):\n",
" # 순수하게 Policy gradient로 구성\n",
" def __init__(self, num_state):\n",
" super(PGNET, self).__init__()\n",
" \n",
" self.fc_in = nn.Linear(num_state, 24)\n",
" self.fc_hidden = nn.Linear(24, 36)\n",
" self.fc_out = nn.Linear(36, 1)\n",
" \n",
" def forward(self, x):\n",
" x = F.relu(self.fc_in(x))\n",
" x = F.relu(self.fc_hidden(x))\n",
" x = TC.sigmoid(self.fc_out(x))\n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"class PGNET_MACHINE(PGNET):\n",
" # Policy gradient를 실제 사용하기 위해 필요한 변환을 고려함\n",
" def __init__(self, num_state, render_flag=False):\n",
" self.forget_factor = 0.99\n",
" self.learning_rate = 0.01\n",
" self.num_episode = 5000 \n",
" self.num_batch = 5\n",
" self.render_flag = render_flag\n",
" self.steps_in_batch = 0\n",
" self.episode_durations = []\n",
" \n",
" super(PGNET_MACHINE, self).__init__(num_state) \n",
" self.optimizer = TC.optim.RMSprop(self.parameters(), lr=self.learning_rate) \n",
" self.init_buff() \n",
" \n",
" def forward(self, state):\n",
" state_var = Variable(TC.from_numpy(state).float())\n",
" prob = super(PGNET_MACHINE, self).forward(state_var)\n",
" # check this function to know what the meaing of log_prob. Is it log(prob)?\n",
" return Bernoulli(prob)\n",
" \n",
" def push_buff_done(self, reward, state, action, done_flag=False):\n",
" if done_flag: # devide between episodes\n",
" self.reward_buff.append(0)\n",
" else:\n",
" self.reward_buff.append(reward)\n",
" self.state_buff.append(state)\n",
" self.action_buff.append(action)\n",
" \n",
" def pull_buff(self, ii):\n",
" return self.reward_buff[ii], self.state_buff[ii], self.action_buff[ii]\n",
" \n",
" def init_buff(self):\n",
" self.reward_buff = []\n",
" self.state_buff = []\n",
" self.action_buff = []\n",
" \n",
" def transform_discount_reward(self, steps):\n",
" future_reward = 0\n",
" for ii in reversed(range(steps)):\n",
" if self.reward_buff[ii] == 0:\n",
" future_reward = 0\n",
" else:\n",
" future_reward = future_reward * self.forget_factor + self.reward_buff[ii]\n",
" self.reward_buff[ii] = future_reward\n",
" list_norm_inplace(self.reward_buff)\n",
" \n",
" def train(self, steps):\n",
" self.transform_discount_reward(steps)\n",
" \n",
" self.optimizer.zero_grad()\n",
" for ii in range(steps):\n",
" reward, state, action = self.pull_buff(ii)\n",
" #state_var = Variable(TC.from_numpy(state).float())\n",
" action_var = Variable(TC.FloatTensor([float(action)]))\n",
" #policy = self.forward(state_var)\n",
" policy = self.forward(state)\n",
" loss = -policy.log_prob(action_var) * reward \n",
" loss.backward()\n",
" self.optimizer.step()\n",
" \n",
" self.init_buff()\n",
"\n",
" def step(self, env, state, ee, ii, ee_duration=100): \n",
" policy = self.forward(state)\n",
" action = policy.sample().data.numpy().astype(int)[0]\n",
"\n",
" next_state, reward, done_flag, _ = env.step(action)\n",
" if self.render_flag: \n",
" env.render() \n",
" self.push_buff_done(reward, state, action, done_flag)\n",
"\n",
" self.steps_in_batch += 1\n",
" state = next_state\n",
" \n",
" return state, done_flag\n",
" \n",
" def run_episode(self, env, ee):\n",
" state = env.reset() \n",
" for ii in count(): \n",
" state, done_flag = self.step(env, state, ee, ii, ee_duration=100)\n",
" if done_flag:\n",
" plot_durations_ii(ii, self.episode_durations, ee, ee_duration=100)\n",
" break\n",
"\n",
" def train_episode(self, ee):\n",
" if ee > 0 and ee % self.num_batch == 0:\n",
" self.train(self.steps_in_batch) \n",
" self.steps_in_batch = 0 \n",
" \n",
" def run(self, env):\n",
" for ee in range(self.num_episode):\n",
" self.run_episode(env, ee)\n",
" self.train_episode(ee)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def main():\n",
" env = gym.make('CartPole-v0') \n",
" mypgnet = PGNET_MACHINE(env.observation_space.shape[0], render_flag=False)\n",
" mypgnet.run(env) \n",
" env.close() "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"main()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "pytorch",
"language": "python",
"name": "pytorch"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment