close_btn
로그인, 회원가입후 더 많은 혜택을 누리세요 로그인 회원가입 닫기

2016.07.14 Leewoongwon & Leeyoungmoo


Reinforcement Learning 그리고 OpenAI

 

<Contents>

 

1. Introduction to OpenAI

 

2-1. Intro to Reinforcement Learning (1) MDP & Value Function

2-2. Intro to Reinforcement Learning (2) Q Learning

 

3-1. CartPole with Deep Q Learning (1) CartPole example  

3-2. CartPole with Deep Q Learning (2) DQN(Deep Q-Networks)

3-3. CartPole with Deep Q Learning (3) TensorFlow

3-4. CartPole with Deep Q Learning (4) Code review

 

4-1. CartPole with Policy Gadient (1) Policy Gradient

4-2. CartPole with Policy Gadient (2) Code review

 

5-1. about Atari games

5-2. Atari "Pong"

5-3. Atari "Breakout"

 

6. MuJoCo

 

 


3-4. CartPole with Deep Q Learning (4) Code review

코드분석 부분은 이영무 연구원님이 작성하시고 나머지는 제가 작성하였습니다.

 

1. Code의 출처

 

https://gym.openai.com/envs/CartPole-v0

Screenshot from 2016-07-14 16:46:39.png

 

OpenAI의 장점은 서로의 코드를 공유할 수 있다는 것입니다. 강화학습을 시작하는 입장으로서 코드로 어떻게 강화학습을 구현할 지 감이 잘 안오는데 다른 사람이 해놓은 코드를 분석하면서 시작하면 도움이 될 것 같습니다. 많은 코드 중에서 DQN으로 CartPole문제를 푼 코드를 분석해보겠습니다.

 

https://github.com/lbbc1117/ClassicControlDQN/blob/master/cart_pole.py

 

 

2. Code의 전체적인 구조

코드의 내부를 파헤쳐보기 전에 전체적인 구조를 한 번 살펴보겠습니다. 코드 자체는 200줄로 짧은 편입니다. 하지만 저는 구조가 머리속에 잡혀야 코드가 좀 읽히는 편이라 구조부터 파악해 보았습니다.

Screenshot from 2016-07-14 17:23:50.png

 

위 그림과 같이 DQN코드는 구성되어 있습니다. Import에서는 필요한 여러가지 라이브러리들을 불러오는 것이고 Train은 말 그대로 agent를 훈련시키는 부분으로서 Learning의 부분입니다. 그 Train은 option이라는 말 그대로 state에 대한 정의, 여러가지 계수들의 정의들에 대한 부분을 포함하고, Q learning을 하는 agent의 구조 또한 포함하고 있습니다. Train 내부에 TensorFlow를 사용하여 계산하는 부분도 들어있습니다. 조금 더 큰 그림에서 Main이 이러한 함수를 가져와서 전체적인 강화학습을 진행하게 됩니다.

 

그러면 Agent가 Learning을 하는 과정에 대해서도 머리속에 그려보는 과정을 거쳐봅시다.

 

David Silver교수님의 강의에서 첫 번째 강화학습을 소개하는 강의에서 나온 그림을 다시 생각해봅시다.

https://youtu.be/2pWv7GOvuf0?list=PL5X3mDkKaJrL42i_jhE4N-p6E2Ol62Ofa

Screenshot from 2016-07-14 17:48:06.png

 

 

위 그림을 토대로 코드의 learning구조를 그려보겠습니다.

 

Screenshot from 2016-07-20 02:59:28.png

 

 

저번 글에서 다루었던 Deep Q-Network는 Agent안에 들어있습니다. Agent가 DQN을 거쳐서 나온 Q function의 값을 토대로 epsilon greedy하게 action을 선택하면 Environment가 현재 상태와 action에 따른 reward를 주고 다음 상태를 알려줍니다. 그것이 하나의 training set이 되어서 Replay memory에 저장(2000개까지 저장을 합니다)이 되고 Agent는 그 중에서 random하게 256개의 training set을 뽑아서 TensorFlow를 이용해서 DQN내부의 weight들을 update합니다.  이것을 Experience Replay라고 합니다.

 

Q learning으로 agent는 학습을 하는데 예전 글에서 Q learning이란 Q function을 update할 때는 greedy하게 다음 가능한 Q'중에서 max를 취해서 update하고 실재로 움직일 때는 epsilon greedy하게 움직임으로서 exploration을 보장하는 RL방법이라고 말했었습니다. 여기서는 exploration부분은 agent가 epsilon greedy하게 움직임으로서 해결이 되었지만 Q function을 update하는 부분에서 어떻게 greedy한 action이 들어갔는지에 대한 의문점이 생깁니다.

 

Neural Network를 update할 때는 어떠한 기준으로 update하는데 그 기준이 loss function이라고 저번 글에서 말했었습니다. 여기서는 그 loss funciton이 다음과 같이 정의됩니다. 그 loss function에 들어가는

Q(s',a')에 max를 취함으로서 greedy한 policy로 업데이트하게 되고 그렇게 Q learning이 됩니다.

values1 = tf.reduce_sum(tf.mul(Q1, act), reduction_indices=1)
values2 = rwd + options.GAMMA * tf.reduce_max(Q2, reduction_indices=1)
loss = tf.reduce_mean(tf.square(values1 - values2))

Screenshot from 2016-07-14 18:23:50.png

 

한 번 update하는데  training set 256를 사용한다고 하였습니다. 256개의 value 1과 value 2를 계산하는데

value 2안에 max가 들어가있습니다. 256개의 value 1과 value 2의 차이의 제곱의 평균이 loss function으로 정의됩니다.

 

이러한 강화학습 학습방법을 Deep Q Learning with Experience Replay라고 합니다.


3. Code 파헤치기

맨 위에서 소개드렸던 코드의 구조대로 설명해보겠습니다.

Screenshot from 2016-07-14 17:23:50.png

 


 

  • Import
1
2
3
4
import gymimport tensorflow as tf
import random
import numpy as np
from argparse import ArgumentParser
cs

 

gym : 가장 먼저 openai를 위한 gym패키지가 import되었습니다.

# OpenAI 설치 링크 : http://www.modulabs.co.kr/RL_library/1705

 

tensorflow : DQN을 위해 Deep Network를 위한 tensorflow가 import되었습니다.

# tensorflow가 설치 되어있지 않은 경우 아래 사이트에서 설치 방법 확인 후 설치하시기 바랍니다.

# tensorflow : https://www.tensorflow.org/versions/r0.9/get_started/os_setup.html#download-and-setup

 

random : random하게 무엇인가를 고르거나 뽑고 싶을 때 사용하는 라이브러리입니다.

 

numpy : 행렬계산을 쉽게 만들어주는 패키지입니다.

 

argparse : argument parser를 위한 패키지입니다. 자세한 사용법은 아래 사이트를 참조하시기 바랍니다.

$ argparse: https://docs.python.org/2/library/argparse.html

1
2
3
4
OUT_DIR = 'cartpole-experiment' # default saving directory
MAX_SCORE_QUEUE_SIZE = 100
GAME = 'CartPole-v0'    # name of game
 
cs

OUT_DIR : 녹화한 동영상을 저장할 디렉토리를 설정합니다.

 

MAX_SCORE_QUEUE_SIZE : 마지막 몇 개의 Score를 평균을 내서 평균 Score로 활용할지 지정해줍니다. 

 

GAME : 어떤 환경을 실행할지 결정합니다. 저희는 CartPole을 설정해줍니다.

 

 


  • Option

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def get_options():
    parser = ArgumentParser()
    parser.add_argument('--MAX_EPISODE', type=int, default=3000,
                        help='max number of episodes iteration')
    parser.add_argument('--ACTION_DIM', type=int, default=2,
                        help='number of actions one can take')
    parser.add_argument('--OBSERVATION_DIM', type=int, default=4,
                        help='number of observations one can see')
    parser.add_argument('--GAMMA', type=float, default=0.9,
                        help='discount factor of Q learning')
    parser.add_argument('--INIT_EPS', type=float, default=1.0,
                        help='initial probability for randomly sampling action')
    parser.add_argument('--FINAL_EPS', type=float, default=1e-5,
                        help='finial probability for randomly sampling action')
    parser.add_argument('--EPS_DECAY', type=float, default=0.95,
                        help='epsilon decay rate')
    parser.add_argument('--EPS_ANNEAL_STEPS', type=int, default=10,
                        help='steps interval to decay epsilon')
    parser.add_argument('--LR', type=float, default=1e-4,
                        help='learning rate')
    parser.add_argument('--MAX_EXPERIENCE', type=int, default=2000,
                        help='size of experience replay memory')
    parser.add_argument('--BATCH_SIZE', type=int, default=256,
                        help='mini batch size'),
    parser.add_argument('--H1_SIZE', type=int, default=128,
                        help='size of hidden layer 1')
    parser.add_argument('--H2_SIZE', type=int, default=128,
                        help='size of hidden layer 2')
    parser.add_argument('--H3_SIZE', type=int, default=128,
                        help='size of hidden layer 3')
    options = parser.parse_args()
    return options
 

cs

 

option은 각족 여러가지 선언이나 정의가 되어있는 곳입니다. 각 선언마다 help가 적혀있으므로 따로 설명하지는 않겠습니다. 그 중에서 DNN을 정의하는 부분에 대해서는 설명할 필요가 있을 것 같습니다. 작성자는 다음 홈페이지를 참고해서 neural network를 구성했다고 합니다.

http://www.nervanasys.com/demystifying-deep-reinforcement-learning/

 

hidden layer는 총 3개로서 2개이상이면 DNN이라고 부르기 때문에 DNN입니다. 각 각의 layer는 128개의 node들로 구성이 되어있습니다. activation function으로는 세 개의 hidden layer들은 ReLu function을 이용하고 있고 마지막에 output을 내는 함수에는 TensorFlow의 Squeeze 함수를 사용하고 있습니다. Input으로는 Observation 

  • x : position of cart on the track
  • θ : angle of the pole with the vertical
  • dx/dt : cart velocity
  • dθ/dt : rate of change of the angle

이 들어가게 되고 output으로는 [1,0]아니면 [0,1]의 행렬이 나오게 됩니다. 이것은 action을 의미하는데 왼쪽으로 impact force을 주거나 오른쪽으로 주거나를 의미합니다.

 


  • Q Agent
1
2
3
4
5
6
7
8
9
10
11
12
13
class QAgent:
    
    # A naive neural network with 3 hidden layers and relu as non-linear function.
    def __init__(self, options):
        self.W1 = self.weight_variable([options.OBSERVATION_DIM, options.H1_SIZE])
        self.b1 = self.bias_variable([options.H1_SIZE])
        self.W2 = self.weight_variable([options.H1_SIZE, options.H2_SIZE])
        self.b2 = self.bias_variable([options.H2_SIZE])
        self.W3 = self.weight_variable([options.H2_SIZE, options.H3_SIZE])
        self.b3 = self.bias_variable([options.H3_SIZE])
        self.W4 = self.weight_variable([options.H3_SIZE, options.ACTION_DIM])
        self.b4 = self.bias_variable([options.ACTION_DIM])
 
cs

Q Agent class입니다. 일단 먼저 처음 tensorflow를 이용해 초기화 하는 부분입니다. 3개의 hidden layer를 갖는 Neural Network를 만들게 됩니다. W1, W2, W3, W4는 Weight입니다. 그리고 b1, b2, b3, b4는 bias를 나타냅니다. hidden unit의 갯수는 위에서 argument option에 정의되어 있습니다. default로는 각각 128개의 hidden unit을 갖게 됩니다.

 

1
2
3
4
5
6
7
8
9
# Weights initializer
    def xavier_initializer(self, shape):
        dim_sum = np.sum(shape)
        if len(shape) == 1:
            dim_sum += 1
        bound = np.sqrt(6.0 / dim_sum)
        return tf.random_uniform(shape, minval=-bound, maxval=bound)
 
 
cs

 

세 개의 hidden layer가 있고 각각의 layer 사이에 weight행렬들이 들어있습니다. 바로 w1, w2, w3인데 이 행렬들을 초기화해주는 단계입니다. 초기화하는 방법으로는 Xavier Initialization를 선택하였습니다. 다음 페이지를 참고해주세요. 한 마디로 첫 단추를 잘 메는 방법중의 하나입니다.

http://andyljones.tumblr.com/post/110998971763/an-explanation-of-xavier-initialization

Screenshot from 2016-07-14 18:46:07.png

 

1
2
3
4
5
6
7
8
 # Tool function to create weight variables
    def weight_variable(self, shape):
        return tf.Variable(self.xavier_initializer(shape))
 
    # Tool function to create bias variables
    def bias_variable(self, shape):
        return tf.Variable(self.xavier_initializer(shape))  
 

cs

 

위에서는 initialization방법을 정한 것이고, 이부분에서는 실제로 initialization을 해주는 함수들을 정의한 부분입니다. tf.Variable이라는 함수가 위에서 정의한 xavier_initialization을 이용해 variable들을 initialization하게 됩니다. 

 

 

1
2
3
4
5
6
7
8
9
# Add options to graph
    def add_value_net(self, options):
        observation = tf.placeholder(tf.float32, [None, options.OBSERVATION_DIM])
        
        h3 = tf.nn.relu(tf.matmul(h2, self.W3) + self.b3)
        Q = tf.squeeze(tf.matmul(h3, self.W4) + self.b4)
        return observation, Q
 
 
cs

 

 

이제 network의 세부사항을 정의합니다. 마지막에는 Linear Function(squeeze)이 들어가고, 나머지는 모두 ReLU Function을 이용합니다. 마지막에 tf.squeeze는 network에서 dimension이 1인 부분을 제거한다고 설명이 되어있습니다. 제가 squeeze없이 테스트한 결과 에러 없이 학습이 됐습니다.(즉, 왜 사용했는 지는 잘 모르겠습니다)

https://www.tensorflow.org/versions/r0.9/api_docs/python/array_ops.html#squeeze

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
# Sample action with random rate eps
    def sample_action(self, Q, feed, eps, options):
        act_values = Q.eval(feed_dict=feed)
        if random.random() <= eps:
            # action_index = env.action_space.sample()
            action_index = random.randrange(options.ACTION_DIM)
        else:
            action_index = np.argmax(act_values)
        action = np.zeros(options.ACTION_DIM)
        action[action_index] = 1
        return action
 
 
cs

 

sample_action 함수를 정의하는 부분입니다. 이 함수는 action을 뽑아주는 함수입니다. 위에서 정의한 Q, feed. eps(ilon), options를 받아와서 action을 정해줍니다. epsilon greedy방법을 이용하며 디폴트로 정해진 옵션으로는 처음 epsilon은 1입니다. random value를 생성해서 epsilon보다 작으면 random action을 수행하고, random value가 epsilon보다 크다면 act_values에 저장된 Q value중에서 좀 더 큰 Q value를 갖는 action을 선택합니다. 결과적으로 왼쪽으로 가는 선택을 하면 [1, 0]을 return하고 오른쪽으로 가는 선택을 하면 [0, 1]을 return을 합니다.

 


  • Train
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def train(env):
    
    # Define placeholders to catch inputs and add options
    options = get_options()
    agent = QAgent(options)
    sess = tf.InteractiveSession()
    
    obs, Q1 = agent.add_value_net(options)
    act = tf.placeholder(tf.float32, [None, options.ACTION_DIM])
    rwd = tf.placeholder(tf.float32, [None, ])
    next_obs, Q2 = agent.add_value_net(options)
    
    values1 = tf.reduce_sum(tf.mul(Q1, act), reduction_indices=1)
    values2 = rwd + options.GAMMA * tf.reduce_max(Q2, reduction_indices=1)
    loss = tf.reduce_mean(tf.square(values1 - values2))
    train_step = tf.train.AdamOptimizer(options.LR).minimize(loss)
    
    sess.run(tf.initialize_all_variables())
    
 
cs

 

 

여기서 부터는 Train을 시키는 부분입니다.

 

options = get_options() : 위에서 정의한 get_options() 함수를 통해 옵션을 정의합니다.

agent = QAgent(options) : QAgent class를 생성합니다.

sess = tf.InteractiveSession() : InteractiveSession()을 생성합니다. 이 부분에 대해서는 저번 글에서 설명했습니다.

 

 

obs, Q1 = agent.add_value_net(options) : add_value_net이라는 함수는 agent 정의부분에 나와있습니다. observation을 넣으면 Q value가 나오는 함수 add_value_net의 형태만 여기서 지정해주는 것입니다. 따라서 밑에 next_obs, Q2 또한 같은 형태인 것입니다. observation이 같은 neural network를 통과해서  Q-value 가 나오는 것인데 단지 한 스텝 뒤인 것만이 차이가 있습니다.

 

act = tf.placeholder(tf.float32, [None, options.ACTION_DIM])

rwd = tf.placeholder(tf.float32, [None, ]) : action과 reward가 저장될 공간을 지정해주는 부분입니다.

 

values1 = tf.reduce_sum(tf.mul(Q1, act), reduction_indices=1)

values2 = rwd + options.GAMMA * tf.reduce_max(Q2, reduction_indices=1)

loss = tf.reduce_mean(tf.square(values1 - values2))

loss function의 정의 부분은 위에서 설명했기 때문에 넘어가겠습니다.

 

train_step = tf.train.AdamOptimizer(options.LR).minimize(loss)

neural networks의 parameter들을 update하는 방법은 Back Propagation입니다. 하지만 그 정도와 방향을 정하는 것은 optimizer인데 DQN강의에서 그 중에서 가장 교과서적인 방법인 Stochastic Gradient Descent라고 말했었습니다. 하지만 실재로는 Adam과 RMSprop을 많이 사용하는데 기본적인 개념은 다음과 같습니다. gradient를 가진다는 것은 어떠한 속도를 가진다고도 생각할 수 있는데 물리라고 생각해보면 운동하는 물체의 운동 관성, 즉 momentum을 고려해준다는 것입니다. 그러한 방법을 momentum update라고 합니다. 또한 gradient를 따라서 descent하는 정도를 learning rate라고 하는데 그 learning rate가 정해져 있는 것이 아니고 시간이 지날수록 decay시키는 방법을 Adaprop이라고 합니다. 이때 그 decayed 된 learning rate를 일종의 필터링을 거쳐서 사용하는 것이 RMSprop이고 거기에 momentum효과를 더하면 그것이 Adam optimizer가 됩니다. 자세한 내용은 다음 논문을 보시면 될 것 같습니다.

https://arxiv.org/pdf/1412.6980.pdf

 

sess.run(tf.initialize_all_variables())

말 그대로 모든 변수를 초기화해주는 부분입니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Some initial local variables
    feed = {}
    eps = options.INIT_EPS
    global_step = 0
    exp_pointer = 0
    learning_finished = False
    
    # The replay memory
    obs_queue = np.empty([options.MAX_EXPERIENCE, options.OBSERVATION_DIM])
    act_queue = np.empty([options.MAX_EXPERIENCE, options.ACTION_DIM])
    rwd_queue = np.empty([options.MAX_EXPERIENCE])
    next_obs_queue = np.empty([options.MAX_EXPERIENCE, options.OBSERVATION_DIM])
    
    # Score cache
    score_queue = []
cs

 

6번째 줄까지는 몇 가지의 변수들을 정의해줍니다. feed에 대해서는 저번 글에서 설명했습니다. 현재 코드는 experience replay를 할 것인데 만약 같은 episode안에서만 순서대로 학습을 한다면 편향되는 효과가 있어서 제대로 학습이 되지 않을 수도 있습니다. 따라서 MAX_EXPERIENCE를 정해놓고(2000번) 거기에 training set을 하나씩 저장을 해서 그 중에서 랜덤으로 256개를 뽑아서 학습합니다. training set은 [ obs act rwd next_obs ]로 이루어져 있고 각각의 저장되는 queue를 정의해줍니다. score의 queue또한 저장해줍니다.

 

 

1
2
3
4
5
6
7
8
# The episode loop
    for i_episode in xrange(options.MAX_EPISODE):
        
        observation = env.reset()
        done = False
        score = 0
        sum_loss_value = 0
 
cs

 

MAX_EPISODE는 3000으로서 3000번까지 CartPole을 Play할 수 있습니다.

처음에 observation을 reset해주고 episode가 끝나기 전까지는 done=false입니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# The step loop
        while not done:
            global_step += 1
            if global_step % options.EPS_ANNEAL_STEPS == 0 and eps > options.FINAL_EPS:
                eps = eps * options.EPS_DECAY
            env.render()
            
            obs_queue[exp_pointer] = observation
            action = agent.sample_action(Q1, {obs : np.reshape(observation, (1-1))}, eps, options)
            act_queue[exp_pointer] = action
            observation, reward, done, _ = env.step(np.argmax(action))
            
            score += reward
            reward = score  # Reward will be the accumulative score
            
            if done and score<200 :
                reward = -500   # If it fails, punish hard
                observation = np.zeros_like(observation)
            
            rwd_queue[exp_pointer] = reward
            next_obs_queue[exp_pointer] = observation
    
            exp_pointer += 1
            if exp_pointer == options.MAX_EXPERIENCE:
                exp_pointer = 0 # Refill the replay memory if it is full
    
            if global_step >= options.MAX_EXPERIENCE:
                rand_indexs = np.random.choice(options.MAX_EXPERIENCE, options.BATCH_SIZE)
                feed.update({obs : obs_queue[rand_indexs]})
                feed.update({act : act_queue[rand_indexs]})
                feed.update({rwd : rwd_queue[rand_indexs]})
                feed.update({next_obs : next_obs_queue[rand_indexs]})
                if not learning_finished:   # If not solved, we train and get the step loss
                    step_loss_value, _ = sess.run([loss, train_step], feed_dict = feed)
                else:   # If solved, we just get the step loss
                    step_loss_value = sess.run(loss, feed_dict = feed)
                # Use sum to calculate average loss of this episode
                sum_loss_value += step_loss_value
 
cs

 

while not done:
episode중간에
 
            global_step += 1
한 스텝씩 진행이 될 때마다 global_step에 1씩 더해주고
 
            if global_step % options.EPS_ANNEAL_STEPS == 0 and eps > options.FINAL_EPS:
EPS_ANNEAL_STEPS(10스텝)이 지날 때마다
 
                eps = eps * options.EPS_DECAY
epsilon greedy의 epsilon을 0.95씩 곱하며 decay해줍니다.
 
            env.render()
현재 상황을 화면으로 보여줍니다.
 
            obs_queue[exp_pointer] = observation

observation값을 obs_queue에 차례대로 차곡차곡 저장해나갑니다. exp_pointer는 그 순서인데

그 이유는 오래된 observation부터 없앨 것이기 때문입니다.

 

            action = agent.sample_action(Q1, {obs : np.reshape(observation, (1-1))}, eps, options)

Action은 agent class안의 sample_action이라는 함수를 통해서 정하게 됩니다. epsilon greedy하게 현재 obs

가 DQN을 통과하여 나온 Q값을 바탕으로 action을 정합니다.

 

            act_queue[exp_pointer] = action
그 action을 순서대로 저장합니다. 다시 한 번 말하자면 이렇게 저장하는 이유는 experience replay때문입니다
 
            observation, reward, done, _ = env.step(np.argmax(action))
다음은 environment의 코드 중 일부입니다. env.step이라는 함수에 대한 정의 중에서 몇 줄만 가져왔습니다.
1
2
3
4
5
6
7
def _step(self, action):
 
    state = self.state
    x, x_dot, theta, theta_dot = state
    force = self.force_mag if action==1 else -self.force_mag
 
    return np.array(self.state), reward, done, {}
cs

즉, 현재 state와 action을 받으면 cart에 force_mag을 그 action에 맞게 가해주고 다음 state와 reward를

보여줍니다. episode가 끝나지 않았을 경우에 done은 false로 return합니다.

 
            score += reward
            reward = score  # Reward will be the accumulative score
episode가 끝나지 않고 한 스텝 더 나아가면 reward는 1이 더해지고 그 값을 score로 저장합니다.
이 score은 replay memory에 들어가게 됩니다.
 
 
그렇게 한 번 스텝을 진행하고 나서서 episode가 끝났을 경우에
            if done and score<200 :
200번 step을 가지 못하고 episode가
 
                reward = -500   # If it fails, punish hard
끝나면 -500 reward를 줌으로서 실패한 에피소드의 절차를 밟지 못하도록 하는 것 같습니다. 사실 그냥 그
reward 그대로 사용해도 될 것 같습니다만 이렇게 하면 더 빨리 수렴은 할 것 같습니다.
                observation = np.zeros_like(observation)
그럴 경우 obs를 0으로 만들어줍니다.
 
하지만 한 스텝을 진행해도 에피소드가 안 끝나면
            rwd_queue[exp_pointer] = reward
리워드를 저장하고
            next_obs_queue[exp_pointer] = observation
observation도 저장하고
            exp_pointer += 1
exp_pointer를 1 증가시키는데 이것은 queue에 저장되는 순서를 가르켜주는 것입니다.
 
            if exp_pointer == options.MAX_EXPERIENCE:
                exp_pointer = 0 # Refill the replay memory if it is full
2000스텝마다 포인터는 리셋되는데 그 결과 새로운 experience는 오래된 experience를 대체하게 됩니다.
 
            if global_step >= options.MAX_EXPERIENCE:
사실상 2000 step전까지는 learning을 하지않고 random하게 움직이며 경험만 쌓습니다.
경험이 2000번 쌓이면 그때부터 batch를 뽑아서 그것을 feed로 줘서 DQN을 학습시킵니다.
                rand_indexs = np.random.choice(options.MAX_EXPERIENCE, options.BATCH_SIZE)
                feed.update({obs : obs_queue[rand_indexs]})
                feed.update({act : act_queue[rand_indexs]})
                feed.update({rwd : rwd_queue[rand_indexs]})
                feed.update({next_obs : next_obs_queue[rand_indexs]})
                if not learning_finished:   # If not solved, we train and get the step loss
                    step_loss_value, _ = sess.run([loss, train_step], feed_dict = feed)
loss함수를 가지고 train_step을 진행합니다. 그리고 그 값을 저장합니다.
                else:   # If solved, we just get the step loss
                    step_loss_value = sess.run(loss, feed_dict = feed)
                # Use sum to calculate average loss of this episode
                sum_loss_value += step_loss_value
그리고 각 스텝마다의 loss값들을 저장합니다.
 
그러다가 200번의 step이 지나가면 에피소드는 끝나는데
 
1
2
3
4
5
6
7
8
9
10
11
print "====== Episode {} ended with score = {}, avg_loss = {} ======".
format(i_episode+1, score, sum_loss_value / score)
        score_queue.append(score)
        if len(score_queue) > MAX_SCORE_QUEUE_SIZE:
            score_queue.pop(0)
            if np.mean(score_queue) > 195
# The threshold of being solved
                learning_finished = True
            else:
                learning_finished = False
        if learning_finished:
            print "Testing !!!"
 
cs
 
episode가 끝나면 몇 번째 episode인지 score는 얼마인지 그리고 loss값의 총 합을 score로 나눈 값을
보여줍니다. 이 값은 아마도 수렴의 정도를 이야기하는 것 같습니다.
 
CartPole에서는 최근 평균 100번의 에피소드 동안의 점수의 합의 평균이 195를 넘으면 learning이 끝납니다. learning이 끝나지 않았으면 다시 처음으로 돌아갑니다.
 
 

  • Main
1
2
3
4
5
6
if __name__ == "__main__":
    env = gym.make(GAME)
    env.monitor.start(OUT_DIR, force=True)
    train(env)
    env.monitor.close()
 
cs

 

main은 따로 설명할 필요가 없을 것 같습니다. 정해진 대로 train을 하고 결과를 정해진 위치에 저장합니다.

 

 

 

 

 


4. Learning해보기 

Eclipse를 켜고 위의 코드를 붙여넣고 실행을 시키면 agent가 학습을 하게됩니다. 텐서플로우 설치안하시면

아래와 같이 오류가 발생합니다.

Screenshot from 2016-07-15 02:00:33.png

 

 

학습을 시작하면 아래와 같이 print가 되는데 처음에 2000번의 step이 지나갈 때 까지는 학습을 하지

않습니다. Replay Memory를 만들고 있는 중이기 때문입니다.

Screenshot from 2016-07-15 02:10:19.png

 

그 이후에는 다음과 같이 학습을 진행합니다.

Screenshot from 2016-07-15 02:10:51.png

 

Screenshot from 2016-07-15 02:24:56.png

 

 

이렇게 DQN코드에 대해서 살펴보았습니다. 다음 글에서는 Policy Gradient에 대해서 다루겠습니다

번호 제목 글쓴이 날짜 조회 수
공지 강화학습 (Reinforcement Learning) 연구실 OpenRL 모임 안내 모두의연구소 2016.06.12 1300
22 softmax action result에 대한 reward 김상범 2017.10.31 255
21 강화학습 논문 웹사이트 모음 xelgana 2016.10.28 1548
20 Monte-Carlo Tree Search 코드 [3] file 이영무 2016.10.06 1866
19 2016. 9. 1. Asynchronous 발표 자료 [1] file 최한철 2016.09.10 412
18 2016. 9. 1. 발표자료 [3] 최한철 2016.08.29 532
17 Fundamental of Reinforcement Learning 링크 이웅원 2016.08.24 1093
16 2016.08.18 OpenRL 발표자료 file 이웅원 2016.08.17 758
15 강화학습 그리고 OpenAI - 4: CartPole with Policy Gradient (2) Code Review [5] file 이웅원 2016.07.20 5399
14 강화학습 그리고 OpenAI - 4: CartPole with Policy Gradient (1) Policy Gradient [9] file 이웅원 2016.07.15 10661
» 강화학습 그리고 OpenAI - 3: CartPole with Deep Q Learning (4) Code Review file 이웅원 2016.07.14 8420
12 강화학습 그리고 OpenAI - 3: CartPole with Deep Q Learning (3) TensorFlow 이웅원 2016.07.13 3887
11 강화학습 그리고 OpenAI - 3: CartPole with Deep Q Learning (2) DQN file 이웅원 2016.07.13 5947
10 강화학습 그리고 OpenAI - 3: CartPole with Deep Q Learning (1) CartPole example file 이웅원 2016.07.12 6604
9 DQN 발표자료 file 플룻 2016.07.11 966
8 강화학습 그리고 OpenAI - 2: Intro to Reinforcement Learning (2) Q Learning [4] file 이웅원 2016.07.08 16143
7 강화학습 그리고 OpenAI - 2: Intro to Reinforcement Learning (1) MDP &Value Function [2] file 이웅원 2016.07.04 17414
6 강화학습 그리고 OpenAI - 1: Introduction to OpenAI [3] file 이웅원 2016.07.01 20211
5 Reinforcement Learning by Sutton Chapter 5~16 file 마르코프김 2016.07.01 579
4 Reinforcement Learning by Sutton Chapter 1~4 [1] file 마르코프김 2016.06.30 2212