Deep learning

[Reinforcement Learning / learn article] Model-Based RL (CartPole)

JaykayChoi 2017. 4. 10. 22:08

이번에는 Model-Based Reinforcement Learning 에 대한 포스팅입니다.

https://medium.com/@awjuliani/simple-reinforcement-learning-with-tensorflow-part-3-model-based-rl-9a6fe0cce99


이 포스팅에서는 Model-Based 라는 새로운 개념이 소개됩니다. 

여기서 말하는 모델이란 실제 환경의 dynamics 을 배운 신경망을 의미합니다. 이렇게 만들어진 모델은 실제 환경 대신에 에이전트에게 환경과 행동에 따른 결과 정보를 제공하여 에이전트가 학습될 수 있게 합니다. 사실 gym 에서 제공하는 게임의 경우 실제 환경을 쉽게 이용할 수 있지만 실제 환경을 이용하기 힘든 상황에서는 이 방법이 유용할 수 있을 것입니다.


이런 모델을 학습하기 위해 초반에는 에이전트를 학습하는 것 처럼 실제 환경을 이용해 모델을 학습시키고 어느 정도 모델이 학습된 이후에는 학습된 모델을 통해 에이전트를 학습시킬 수 있습니다.


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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
import numpy as np
import _pickle as pickle
import tensorflow as tf
import matplotlib.pyplot as plt
import gym
 
env = gym.make('CartPole-v0')
 
# hyperparameters
= 8 # number of hidden layer neurons
learning_rate = 1e-2
gamma = 0.99 # discount factor for reward
decay_rate = 0.99 # decay factor for RMSProp leaky sum of grad^2
resume = False # resume from previous checkpoint?
 
model_bs = 3 # Batch size when learning from model
real_bs = 3 # Batch size when learning from real environment
 
# model initialization
= 4 # input dimensionality
 
 
tf.reset_default_graph()
observations = tf.placeholder(tf.float32, [None,4] , name="input_x")
W1 = tf.get_variable("W1", shape=[4, H],
           initializer=tf.contrib.layers.xavier_initializer())
layer1 = tf.nn.relu(tf.matmul(observations,W1))
W2 = tf.get_variable("W2", shape=[H, 1],
           initializer=tf.contrib.layers.xavier_initializer())
score = tf.matmul(layer1,W2)
probability = tf.nn.sigmoid(score)
 
tvars = tf.trainable_variables()
input_y = tf.placeholder(tf.float32,[None,1], name="input_y")
advantages = tf.placeholder(tf.float32,name="reward_signal")
adam = tf.train.AdamOptimizer(learning_rate=learning_rate)
W1Grad = tf.placeholder(tf.float32,name="batch_grad1")
W2Grad = tf.placeholder(tf.float32,name="batch_grad2")
batchGrad = [W1Grad,W2Grad]
loglik = tf.log(input_y*(input_y - probability) + (1 - input_y)*(input_y + probability))
loss = -tf.reduce_mean(loglik * advantages)
newGrads = tf.gradients(loss,tvars)
updateGrads = adam.apply_gradients(zip(batchGrad,tvars))
 
 
mH = 256 # model layer size
 
input_data = tf.placeholder(tf.float32, [None, 5])
with tf.variable_scope('rnnlm'):
    softmax_w = tf.get_variable("softmax_w", [mH, 50])
    softmax_b = tf.get_variable("softmax_b", [50])
 
previous_state = tf.placeholder(tf.float32, [None,5] , name="previous_state")
W1M = tf.get_variable("W1M", shape=[5, mH],
           initializer=tf.contrib.layers.xavier_initializer())
B1M = tf.Variable(tf.zeros([mH]),name="B1M")
layer1M = tf.nn.relu(tf.matmul(previous_state,W1M) + B1M)
W2M = tf.get_variable("W2M", shape=[mH, mH],
           initializer=tf.contrib.layers.xavier_initializer())
B2M = tf.Variable(tf.zeros([mH]),name="B2M")
layer2M = tf.nn.relu(tf.matmul(layer1M,W2M) + B2M)
wO = tf.get_variable("wO", shape=[mH, 4],
           initializer=tf.contrib.layers.xavier_initializer())
wR = tf.get_variable("wR", shape=[mH, 1],
           initializer=tf.contrib.layers.xavier_initializer())
wD = tf.get_variable("wD", shape=[mH, 1],
           initializer=tf.contrib.layers.xavier_initializer())
 
bO = tf.Variable(tf.zeros([4]),name="bO")
bR = tf.Variable(tf.zeros([1]),name="bR")
bD = tf.Variable(tf.ones([1]),name="bD")
 
 
predicted_observation = tf.matmul(layer2M,wO,name="predicted_observation"+ bO
predicted_reward = tf.matmul(layer2M,wR,name="predicted_reward"+ bR
predicted_done = tf.sigmoid(tf.matmul(layer2M,wD,name="predicted_done"+ bD)
 
true_observation = tf.placeholder(tf.float32,[None,4],name="true_observation")
true_reward = tf.placeholder(tf.float32,[None,1],name="true_reward")
true_done = tf.placeholder(tf.float32,[None,1],name="true_done")
 
 
predicted_state = tf.concat([predicted_observation,predicted_reward,predicted_done], 1)
 
observation_loss = tf.square(true_observation - predicted_observation)
 
reward_loss = tf.square(true_reward - predicted_reward)
 
done_loss = tf.multiply(predicted_done, true_done) + tf.multiply(1-predicted_done, 1-true_done)
done_loss = -tf.log(done_loss)
 
model_loss = tf.reduce_mean(observation_loss + done_loss + reward_loss)
 
modelAdam = tf.train.AdamOptimizer(learning_rate=learning_rate)
updateModel = modelAdam.minimize(model_loss)
 
 
def resetGradBuffer(gradBuffer):
    for ix, grad in enumerate(gradBuffer):
        gradBuffer[ix] = grad * 0
    return gradBuffer
 
 
def discount_rewards(r):
    """ take 1D float array of rewards and compute discounted reward """
    discounted_r = np.zeros_like(r)
    running_add = 0
    for t in reversed(range(0, r.size)):
        running_add = running_add * gamma + r[t]
        discounted_r[t] = running_add
    return discounted_r
 
 
# This function uses our model to produce a new state when given a previous state and action
def stepModel(sess, xs, action):
    toFeed = np.reshape(np.hstack([xs[-1][0], np.array(action)]), [15])
    myPredict = sess.run([predicted_state], feed_dict={previous_state: toFeed})
    reward = myPredict[0][:, 4]
    observation = myPredict[0][:, 0:4]
    observation[:, 0= np.clip(observation[:, 0], -2.42.4)
    observation[:, 2= np.clip(observation[:, 2], -0.40.4)
    doneP = np.clip(myPredict[0][:, 5], 01)
    if doneP > 0.1 or len(xs) >= 300:
        done = True
    else:
        done = False
    return observation, reward, done
 
 
xs, drs, ys, ds = [], [], [], []
running_reward = None
reward_sum = 0
episode_number = 1
real_episodes = 1
init = tf.initialize_all_variables()
batch_size = real_bs
 
drawFromModel = False  # When set to True, will use model for observations
trainTheModel = True  # Whether to train the model
trainThePolicy = False  # Whether to train the policy
switch_point = 1
 
# Launch the graph
with tf.Session() as sess:
    rendering = False
    sess.run(init)
    observation = env.reset()
    x = observation
    gradBuffer = sess.run(tvars)
    gradBuffer = resetGradBuffer(gradBuffer)
 
    while episode_number <= 5000:
        # Start displaying environment once performance is acceptably high.
        if (reward_sum / batch_size > 150 and drawFromModel == False) or rendering == True:
            env.render()
            rendering = True
 
        x = np.reshape(observation, [14])
 
        tfprob = sess.run(probability, feed_dict={observations: x})
        action = 1 if np.random.uniform() < tfprob else 0
 
        # record various intermediates (needed later for backprop)
        xs.append(x)
        y = 1 if action == 0 else 0
        ys.append(y)
 
        # step the  model or real environment and get new measurements
        if drawFromModel == False:
            observation, reward, done, info = env.step(action)
        else:
            observation, reward, done = stepModel(sess, xs, action)
 
        reward_sum += reward
 
        ds.append(done * 1)
        drs.append(reward)  # record reward (has to be done after we call step() to get reward for previous action)
 
        if done:
 
            if drawFromModel == False:
                real_episodes += 1
            episode_number += 1
 
            # stack together all inputs, hidden states, action gradients, and rewards for this episode
            epx = np.vstack(xs)
            epy = np.vstack(ys)
            epr = np.vstack(drs)
            epd = np.vstack(ds)
            xs, drs, ys, ds = [], [], [], []  # reset array memory
 
            if trainTheModel == True:
                actions = np.array([np.abs(y - 1for y in epy][:-1])
                state_prevs = epx[:-1, :]
                state_prevs = np.hstack([state_prevs, actions])
                state_nexts = epx[1:, :]
                rewards = np.array(epr[1:, :])
                dones = np.array(epd[1:, :])
                state_nextsAll = np.hstack([state_nexts, rewards, dones])
 
                feed_dict = {previous_state: state_prevs, true_observation: state_nexts, true_done: dones,
                             true_reward: rewards}
                loss, pState, _ = sess.run([model_loss, predicted_state, updateModel], feed_dict)
            if trainThePolicy == True:
                discounted_epr = discount_rewards(epr).astype('float32')
                discounted_epr -= np.mean(discounted_epr)
                discounted_epr /= np.std(discounted_epr)
                tGrad = sess.run(newGrads, feed_dict={observations: epx, input_y: epy, advantages: discounted_epr})
 
                # If gradients becom too large, end training process
                if np.sum(tGrad[0== tGrad[0]) == 0:
                    break
                for ix, grad in enumerate(tGrad):
                    gradBuffer[ix] += grad
 
            if switch_point + batch_size == episode_number:
                switch_point = episode_number
                if trainThePolicy == True:
                    sess.run(updateGrads, feed_dict={W1Grad: gradBuffer[0], W2Grad: gradBuffer[1]})
                    gradBuffer = resetGradBuffer(gradBuffer)
 
                running_reward = reward_sum if running_reward is None else running_reward * 0.99 + reward_sum * 0.01
                if drawFromModel == False:
                    print('World Perf: Episode %f. Reward %f. action: %f. mean reward %f.' % (
                    real_episodes, reward_sum / real_bs, action, running_reward / real_bs))
                    if reward_sum / batch_size > 200:
                        break
                reward_sum = 0
 
                # Once the model has been trained on 100 episodes, we start alternating between training the policy
                # from the model and training the model from the real environment.
                if episode_number > 100:
                    drawFromModel = not drawFromModel
                    trainTheModel = not trainTheModel
                    trainThePolicy = not trainThePolicy
 
            if drawFromModel == True:
                observation = np.random.uniform(-0.10.1, [4])  # Generate reasonable starting point
                batch_size = model_bs
            else:
                observation = env.reset()
                batch_size = real_bs
 
print(real_episodes)
 
 
plt.figure(figsize=(812))
for i in range(6):
    plt.subplot(622*+ 1)
    plt.plot(pState[:,i])
    plt.subplot(6,2,2*i+1)
    plt.plot(state_nextsAll[:,i])
plt.tight_layout()
cs



직전 포스팅과 다르게 decay_rate 라는 인자가 추가되었습니다. 이는 RMS propagation 을 위한 인자로써 RMS 는 root mean square 의 약자입니다.

기존의 propagation이 error을 계산할 때 오차의 제곱의 평균값을 이용했다면 RMS 는 오차의 제곱의 평균값에 제곱근을 한 값을 이용하는 방법입니다.

https://en.wikipedia.org/wiki/Root-mean-square_deviation

그런데 이 포스팅에서는 인자만 추가하고 RMS propagation 을 사용하지는 않았네요.

model_bs 와 real_bs 는 각각 모델 환경과 실제 환경인 경우의 batch_size 값입니다.

batch_size 는 직전 포스팅과 마찬가지로 몇 번의 에피소드에 한 번씩 에이전트를 학습시킬지에 대한 인자입니다.

# hyperparameters
= 8 # number of hidden layer neurons
learning_rate = 1e-2
gamma = 0.99 # discount factor for reward
decay_rate = 0.99 # decay factor for RMSProp leaky sum of grad^2
resume = False # resume from previous checkpoint?
 
model_bs = 3 # Batch size when learning from model
real_bs = 3 # Batch size when learning from real environment
 
# model initialization
= 4 # input dimensionality
cs



Policy Network 을 구성하는 부분은 직전 포스팅과 내용이 동일합니다.

tf.reset_default_graph()
observations = tf.placeholder(tf.float32, [None,4] , name="input_x")
W1 = tf.get_variable("W1", shape=[4, H],
           initializer=tf.contrib.layers.xavier_initializer())
layer1 = tf.nn.relu(tf.matmul(observations,W1))
W2 = tf.get_variable("W2", shape=[H, 1],
           initializer=tf.contrib.layers.xavier_initializer())
score = tf.matmul(layer1,W2)
probability = tf.nn.sigmoid(score)
 
tvars = tf.trainable_variables()
input_y = tf.placeholder(tf.float32,[None,1], name="input_y")
advantages = tf.placeholder(tf.float32,name="reward_signal")
adam = tf.train.AdamOptimizer(learning_rate=learning_rate)
W1Grad = tf.placeholder(tf.float32,name="batch_grad1")
W2Grad = tf.placeholder(tf.float32,name="batch_grad2")
batchGrad = [W1Grad,W2Grad]
loglik = tf.log(input_y*(input_y - probability) + (1 - input_y)*(input_y + probability))
loss = -tf.reduce_mean(loglik * advantages)
newGrads = tf.gradients(loss,tvars)
updateGrads = adam.apply_gradients(zip(batchGrad,tvars))
cs



이 포스팅에서 가장 핵심인 Model Network 을 구성하는 부분입니다.

먼저 input이 none, 5의 배열로 정의되었습니다. cartPole 의 input이 4개인 것과 다르게 5개로 input이 정의된 이유는 추가적으로 행동에 대한 정보도 같이 받기 때문입니다.

첫 번째 weights W1M 은 5, 256 으로 만들고 previous_state 와 곱한 후 ReLU 처리를 하여 layer1M 을 만듭니다.

여기서 previous_state 은 실제 환경에서 전달받은 값입니다. 이 실제 환경에서 전달받은 상태값을 이용해 얻어지는 step 의 결과의 차이를 줄이는 것이 모델을 학습시키는 방향이 될 것입니다.

두 번째 weights W2M 은 256,256 으로 만들고 layer1M와 곱한 후 마찬가지로 ReLU 처리를 하였습니다.

다음으로 상태에 대한 output 을 내기 위해 256,4 의 w0

보상에 대한 output 을 내기 위해 256,1 의 wR

종료 여부에 대한 output 을 내기 위해 256,1 의 wD 을 만들고

mH = 256 # model layer size
 
input_data = tf.placeholder(tf.float32, [None, 5])
with tf.variable_scope('rnnlm'):
    softmax_w = tf.get_variable("softmax_w", [mH, 50])
    softmax_b = tf.get_variable("softmax_b", [50])
 
previous_state = tf.placeholder(tf.float32, [None,5] , name="previous_state")
W1M = tf.get_variable("W1M", shape=[5, mH],
           initializer=tf.contrib.layers.xavier_initializer())
B1M = tf.Variable(tf.zeros([mH]),name="B1M")
layer1M = tf.nn.relu(tf.matmul(previous_state,W1M) + B1M)
W2M = tf.get_variable("W2M", shape=[mH, mH],
           initializer=tf.contrib.layers.xavier_initializer())
B2M = tf.Variable(tf.zeros([mH]),name="B2M")
layer2M = tf.nn.relu(tf.matmul(layer1M,W2M) + B2M)
wO = tf.get_variable("wO", shape=[mH, 4],
           initializer=tf.contrib.layers.xavier_initializer())
wR = tf.get_variable("wR", shape=[mH, 1],
           initializer=tf.contrib.layers.xavier_initializer())
wD = tf.get_variable("wD", shape=[mH, 1],
           initializer=tf.contrib.layers.xavier_initializer())
 
bO = tf.Variable(tf.zeros([4]),name="bO")
bR = tf.Variable(tf.zeros([1]),name="bR")
bD = tf.Variable(tf.ones([1]),name="bD")
cs

layer2M * wO 을 하여 predicted_observation 

layer2M * wR 을 하여 predicted_reward 

layer2M * wD 을 하여 predicted_done 을 만들어 모델을 통해 상태, 보상, 종료 여부를 얻을 수 있게 신경망을 구성하였습니다.

predicted_observation = tf.matmul(layer2M,wO,name="predicted_observation"+ bO
predicted_reward = tf.matmul(layer2M,wR,name="predicted_reward"+ bR
predicted_done = tf.sigmoid(tf.matmul(layer2M,wD,name="predicted_done"+ bD)
cs



true_observation, true_reward, true_done 은 실제 환경에서 값을 받는 변수들입니다.

true_observation = tf.placeholder(tf.float32,[None,4],name="true_observation")
true_reward = tf.placeholder(tf.float32,[None,1],name="true_reward")
true_done = tf.placeholder(tf.float32,[None,1],name="true_done")
cs



tf.concat 은 배열을 하나의 차원으로 합치는 함수입니다. predicted_observation,predicted_reward,predicted_done 3개를 합쳐 하나의 모델에서의 예측 상태 배열(predicted_state)을 만들었습니다. 

실제 환경의 값과 모델에서의 예측 상태의 차이의 제곱을 통해 observation_loss 을 구합니다.

실제 환경의 보상과 모델에서의 예측 보상의 차이의 제곱을 통해 reward_loss 을 구합니다.

종료 여부 done 은 1 또는 0의 값이기에 조금 다르게 처리하여 done_loss 을 구했습니다. 

이런 loss 들의 평균으로 model_loss 을 구한 후 AdamOptimizer 을 이용하여 loss가 최소화되도록 훈련을 만듭니다.

predicted_state = tf.concat([predicted_observation,predicted_reward,predicted_done], 1)
 
observation_loss = tf.square(true_observation - predicted_observation)
 
reward_loss = tf.square(true_reward - predicted_reward)
 
done_loss = tf.multiply(predicted_done, true_done) + tf.multiply(1-predicted_done, 1-true_done)
done_loss = -tf.log(done_loss)
 
model_loss = tf.reduce_mean(observation_loss + done_loss + reward_loss)
 
modelAdam = tf.train.AdamOptimizer(learning_rate=learning_rate)
updateModel = modelAdam.minimize(model_loss)
cs



gym의 step 과 같은 기능을 하는 모델의 step 함수입니다.

먼저 상태와 행동을 합쳐 toFeed(1, 5) 을 만듭니다. numpy.hstack 은 horizontally 하게 배열을 합치는 함수입니다.

위에서 만든 predicted_state 을 실행시켜 예상값들을 myPredict 에 가져옵니다.

myPredict은 list 로써 1, 6의 배열을 원소로 가지고 있습니다. myPredict가 list이긴 하지만 여기서는 항상 1개의 원소를 가지고 있습니다. 

myPredict 에서 보상과 상태를 가져옵니다. 

reward 는 myPredict[0][:, 4] 으로 1, 6의 배열을 [:, 4] 으로 slicing 함으로써 5번째 값 즉 4번 index 의 값만 가지고 오게 됩니다.

observation 은 myPredict[0] 의 [:, 0:4] 즉 0~3번 index 만 가지와 1, 4의 배열이 됩니다.

numpy.clip 을 통해 상태 값을 일부 조정합니다. clip 은 주어진 최소 최대 값을 넘는 값들을 최소 최대값으로 조정하는 함수입니다.

doneP 는 myPredict[0] 의 [:, 5] 즉 5번 index 값을 0, 1 사이로 clip 하여 가져온 후

값이 0.1을 넘거나 상태(xs)의 개수가 300개를 넘어가면 종료로 처리를 합니다.

# This function uses our model to produce a new state when given a previous state and action
def stepModel(sess, xs, action):
    toFeed = np.reshape(np.hstack([xs[-1][0], np.array(action)]), [15])
    myPredict = sess.run([predicted_state], feed_dict={previous_state: toFeed})
    reward = myPredict[0][:, 4]
    observation = myPredict[0][:, 0:4]
    observation[:, 0= np.clip(observation[:, 0], -2.42.4)
    observation[:, 2= np.clip(observation[:, 2], -0.40.4)
    doneP = np.clip(myPredict[0][:, 5], 01)
    if doneP > 0.1 or len(xs) >= 300:
        done = True
    else:
        done = False
    return observation, reward, done
#cs



처음 batch_size 는 실제 환경의 batch_size 을 사용합니다.

drawFromModel 모델을 사용할지 여부도 처음에는 false 로 합니다.

trainTheModel 모델의 훈련 여부는 true 로 합니다.

trainThePolicy 처음에는 policy(정책)을 학습하지 않도록 false로 합니다. 모델의 효과를 알기 위해 모델로만 에이전트를 학습하기 위함입니다.

switch_point 은 에피소드가 일정 횟수 이상 지나면 정책을 학습하기 위한 count 변수입니다.

나머지 변수들은 직전 포스팅과 동일합니다.

xs, drs, ys, ds = [], [], [], []
running_reward = None
reward_sum = 0
episode_number = 1
real_episodes = 1
init = tf.initialize_all_variables()
batch_size = real_bs
 
drawFromModel = False  # When set to True, will use model for observations
trainTheModel = True  # Whether to train the model
trainThePolicy = False  # Whether to train the policy
switch_point = 1
cs



앞부분은 직전 포스팅과 같고 drawFromModel 값에 따라 실제 환경과 모델 환경을 스위칭 합니다.

        x = np.reshape(observation, [14])
 
        tfprob = sess.run(probability, feed_dict={observations: x})
        action = 1 if np.random.uniform() < tfprob else 0
 
        # record various intermediates (needed later for backprop)
        xs.append(x)
        y = 1 if action == 0 else 0
        ys.append(y)
 
        # step the  model or real environment and get new measurements
        if drawFromModel == False:
            observation, reward, done, info = env.step(action)
        else:
            observation, reward, done = stepModel(sess, xs, action)
cs



보상과 종료 여부를 배열에 담습니다.

        reward_sum += reward
 
        ds.append(done * 1)
        drs.append(reward)  # record reward (has to be done after we call step() to get reward for previous action)
cs



에피소드가 종료되면 실제 환경을 사용했을 경우 real_episodes 에 1을 더합니다.

직전 포스팅과 같이 에피소드 변수 배열들로 기록된 값들을 기록합니다.

        if done:
 
            if drawFromModel == False:
                real_episodes += 1
            episode_number += 1
 
            # stack together all inputs, hidden states, action gradients, and rewards for this episode
            epx = np.vstack(xs)
            epy = np.vstack(ys)
            epr = np.vstack(drs)
            epd = np.vstack(ds)
            xs, drs, ys, ds = [], [], [], []  # reset array memory
cs



모델을 훈련시키기로 했다면

y 를 통해 actions 을 만들고 (여기서 다시 원래대로 1->0, 0->1 으로 원래 action 값으로 변경) 

이전 행동과 상태를 합쳐 state_prevs 을 만듭니다. 이 배열은 none, 5 이며, (none는 종료되기 전 까지 쌓인 행동의 개수)

epx의 0번 index 부터 (last -1) index 까지의 배열입니다.

다음으로 state_nexts 에는 epx 의 1번 index 부터 마지막 index 까지의 값을 할당합니다.

이렇게 이전 상태와 다음 상태를 만듦으로써 만들어진 state_prevs 와 state_nexts 의 동일한 index 에 직전 상태와 직후 상태 즉 환경과 그 환경의 step에 따른 결과를 담아둘 수 있습니다.

그리고 다음 상태, 보상, 종료 여부를 얻은 후 model_loss, predicted_state, updateModel 을 실행시켜 모델을 훈련시킵니다.

            if trainTheModel == True:
                actions = np.array([np.abs(y - 1for y in epy][:-1])
                state_prevs = epx[:-1, :]
                state_prevs = np.hstack([state_prevs, actions])
                state_nexts = epx[1:, :]
                rewards = np.array(epr[1:, :])
                dones = np.array(epd[1:, :])
                state_nextsAll = np.hstack([state_nexts, rewards, dones])
 
                feed_dict = {previous_state: state_prevs, true_observation: state_nexts, true_done: dones,
                             true_reward: rewards}
                loss, pState, _ = sess.run([model_loss, predicted_state, updateModel], feed_dict)
cs



정책을 훈련시키기로 했다면 직전 포스팅과 같이 버퍼에 gradients 을 담아둡니다. 이때 다른 점은 버퍼가 너무 클 경우 종료시킵니다.

            if trainThePolicy == True:
                discounted_epr = discount_rewards(epr).astype('float32')
                discounted_epr -= np.mean(discounted_epr)
                discounted_epr /= np.std(discounted_epr)
                tGrad = sess.run(newGrads, feed_dict={observations: epx, input_y: epy, advantages: discounted_epr})
 
                # If gradients becom too large, end training process
                if np.sum(tGrad[0== tGrad[0]) == 0:
                    break
                for ix, grad in enumerate(tGrad):
                    gradBuffer[ix] += grad
cs



직전 포스팅과 같이 batch_size 에 한 번씩 정책을 훈련시킵니다.

            if switch_point + batch_size == episode_number:
                switch_point = episode_number
                if trainThePolicy == True:
                    sess.run(updateGrads, feed_dict={W1Grad: gradBuffer[0], W2Grad: gradBuffer[1]})
                    gradBuffer = resetGradBuffer(gradBuffer)
cs



모델을 사용하지 않을 경우 보상이 200이 넘을 경우 종료시킵니다.

                running_reward = reward_sum if running_reward is None else running_reward * 0.99 + reward_sum * 0.01
                if drawFromModel == False:
                    print('World Perf: Episode %f. Reward %f. action: %f. mean reward %f.' % (
                    real_episodes, reward_sum / real_bs, action, running_reward / real_bs))
                    if reward_sum / batch_size > 200:
                        break
                reward_sum = 0
cs




100 에피소드가 지난 후 모델을 학습시키도록 (정책도 학습) 변경합니다.

                # Once the model has been trained on 100 episodes, we start alternating between training the policy
                # from the model and training the model from the real environment.
                if episode_number > 100:
                    drawFromModel = not drawFromModel
                    trainTheModel = not trainTheModel
                    trainThePolicy = not trainThePolicy
cs


모델을 사용할 경우 상태를 균일 분포를 통해 초기화 시키고 실제 환경을 사용할 경우 gym 을 이용해  reset 합니다.

            if drawFromModel == True:
                observation = np.random.uniform(-0.10.1, [4])  # Generate reasonable starting point
                batch_size = model_bs
            else:
                observation = env.reset()
                batch_size = real_bs
cs