1+ import tensorflow as tf
2+ import numpy as np
3+ import os
4+ import shutil
5+ from arm_env import ArmEnv
6+
7+
8+ np .random .seed (1 )
9+ tf .set_random_seed (1 )
10+
11+ MAX_EPISODES = 600
12+ MAX_EP_STEPS = 200
13+ LR_A = 1e-4 # learning rate for actor
14+ LR_C = 1e-4 # learning rate for critic
15+ GAMMA = 0.999 # reward discount
16+ REPLACE_ITER_A = 1100
17+ REPLACE_ITER_C = 1000
18+ MEMORY_CAPACITY = 10000
19+ BATCH_SIZE = 16
20+ VAR_MIN = 0.1
21+ RENDER = True
22+ LOAD = True
23+ MODE = ['easy' , 'hard' ]
24+ n_model = 1
25+
26+ env = ArmEnv (mode = MODE [n_model ])
27+ STATE_DIM = env .state_dim
28+ ACTION_DIM = env .action_dim
29+ ACTION_BOUND = env .action_bound
30+
31+ # all placeholder for tf
32+ with tf .name_scope ('S' ):
33+ S = tf .placeholder (tf .float32 , shape = [None , STATE_DIM ], name = 's' )
34+ with tf .name_scope ('A' ):
35+ A = tf .placeholder (tf .float32 , shape = [None , ACTION_DIM ], name = 'a' )
36+ with tf .name_scope ('R' ):
37+ R = tf .placeholder (tf .float32 , [None , 1 ], name = 'r' )
38+ with tf .name_scope ('S_' ):
39+ S_ = tf .placeholder (tf .float32 , shape = [None , STATE_DIM ], name = 's_' )
40+
41+
42+ class Actor (object ):
43+ def __init__ (self , sess , action_dim , action_bound , learning_rate , t_replace_iter ):
44+ self .sess = sess
45+ self .a_dim = action_dim
46+ self .action_bound = action_bound
47+ self .lr = learning_rate
48+ self .t_replace_iter = t_replace_iter
49+ self .t_replace_counter = 0
50+
51+ with tf .variable_scope ('Actor' ):
52+ # input s, output a
53+ self .a = self ._build_net (S , scope = 'eval_net' , trainable = True )
54+
55+ # input s_, output a, get a_ for critic
56+ self .a_ = self ._build_net (S_ , scope = 'target_net' , trainable = False )
57+
58+ self .e_params = tf .get_collection (tf .GraphKeys .GLOBAL_VARIABLES , scope = 'Actor/eval_net' )
59+ self .t_params = tf .get_collection (tf .GraphKeys .GLOBAL_VARIABLES , scope = 'Actor/target_net' )
60+
61+ def _build_net (self , s , scope , trainable ):
62+ with tf .variable_scope (scope ):
63+ init_w = tf .contrib .layers .xavier_initializer ()
64+ init_b = tf .constant_initializer (0.001 )
65+ net = tf .layers .dense (s , 200 , activation = tf .nn .relu6 ,
66+ kernel_initializer = init_w , bias_initializer = init_b , name = 'l1' ,
67+ trainable = trainable )
68+ net = tf .layers .dense (net , 200 , activation = tf .nn .relu6 ,
69+ kernel_initializer = init_w , bias_initializer = init_b , name = 'l2' ,
70+ trainable = trainable )
71+ net = tf .layers .dense (net , 10 , activation = tf .nn .relu ,
72+ kernel_initializer = init_w , bias_initializer = init_b , name = 'l3' ,
73+ trainable = trainable )
74+ with tf .variable_scope ('a' ):
75+ actions = tf .layers .dense (net , self .a_dim , activation = tf .nn .tanh , kernel_initializer = init_w ,
76+ name = 'a' , trainable = trainable )
77+ scaled_a = tf .multiply (actions , self .action_bound , name = 'scaled_a' ) # Scale output to -action_bound to action_bound
78+ return scaled_a
79+
80+ def learn (self , s , a ): # batch update
81+ self .sess .run (self .train_op , feed_dict = {S : s , A : a })
82+ if self .t_replace_counter % self .t_replace_iter == 0 :
83+ self .sess .run ([tf .assign (t , e ) for t , e in zip (self .t_params , self .e_params )])
84+ self .t_replace_counter += 1
85+
86+ def choose_action (self , s ):
87+ s = s [np .newaxis , :] # single state
88+ return self .sess .run (self .a , feed_dict = {S : s })[0 ] # single action
89+
90+ def add_grad_to_graph (self , a_grads ):
91+ with tf .variable_scope ('policy_grads' ):
92+ self .policy_grads = tf .gradients (ys = self .a , xs = self .e_params , grad_ys = a_grads )
93+
94+ with tf .variable_scope ('A_train' ):
95+ opt = tf .train .RMSPropOptimizer (- self .lr / BATCH_SIZE ) # (- learning rate) for ascent policy, div to take mean
96+ self .train_op = opt .apply_gradients (zip (self .policy_grads , self .e_params ))
97+
98+
99+ class Critic (object ):
100+ def __init__ (self , sess , state_dim , action_dim , learning_rate , gamma , t_replace_iter , a_ ):
101+ self .sess = sess
102+ self .s_dim = state_dim
103+ self .a_dim = action_dim
104+ self .lr = learning_rate
105+ self .gamma = gamma
106+ self .t_replace_iter = t_replace_iter
107+ self .t_replace_counter = 0
108+
109+ with tf .variable_scope ('Critic' ):
110+ # Input (s, a), output q
111+ self .q = self ._build_net (S , A , 'eval_net' , trainable = True )
112+
113+ # Input (s_, a_), output q_ for q_target
114+ self .q_ = self ._build_net (S_ , a_ , 'target_net' , trainable = False ) # target_q is based on a_ from Actor's target_net
115+
116+ self .e_params = tf .get_collection (tf .GraphKeys .GLOBAL_VARIABLES , scope = 'Critic/eval_net' )
117+ self .t_params = tf .get_collection (tf .GraphKeys .GLOBAL_VARIABLES , scope = 'Critic/target_net' )
118+
119+ with tf .variable_scope ('target_q' ):
120+ self .target_q = R + self .gamma * self .q_
121+
122+ with tf .variable_scope ('TD_error' ):
123+ self .loss = tf .reduce_mean (tf .squared_difference (self .target_q , self .q ))
124+
125+ with tf .variable_scope ('C_train' ):
126+ self .train_op = tf .train .RMSPropOptimizer (self .lr ).minimize (self .loss )
127+
128+ with tf .variable_scope ('a_grad' ):
129+ self .a_grads = tf .gradients (self .q , A )[0 ] # tensor of gradients of each sample (None, a_dim)
130+
131+ def _build_net (self , s , a , scope , trainable ):
132+ with tf .variable_scope (scope ):
133+ init_w = tf .contrib .layers .xavier_initializer ()
134+ init_b = tf .constant_initializer (0.01 )
135+
136+ with tf .variable_scope ('l1' ):
137+ n_l1 = 200
138+ w1_s = tf .get_variable ('w1_s' , [self .s_dim , n_l1 ], initializer = init_w , trainable = trainable )
139+ w1_a = tf .get_variable ('w1_a' , [self .a_dim , n_l1 ], initializer = init_w , trainable = trainable )
140+ b1 = tf .get_variable ('b1' , [1 , n_l1 ], initializer = init_b , trainable = trainable )
141+ net = tf .nn .relu6 (tf .matmul (s , w1_s ) + tf .matmul (a , w1_a ) + b1 )
142+ net = tf .layers .dense (net , 200 , activation = tf .nn .relu6 ,
143+ kernel_initializer = init_w , bias_initializer = init_b , name = 'l2' ,
144+ trainable = trainable )
145+ net = tf .layers .dense (net , 10 , activation = tf .nn .relu ,
146+ kernel_initializer = init_w , bias_initializer = init_b , name = 'l3' ,
147+ trainable = trainable )
148+ with tf .variable_scope ('q' ):
149+ q = tf .layers .dense (net , 1 , kernel_initializer = init_w , bias_initializer = init_b , trainable = trainable ) # Q(s,a)
150+ return q
151+
152+ def learn (self , s , a , r , s_ ):
153+ self .sess .run (self .train_op , feed_dict = {S : s , A : a , R : r , S_ : s_ })
154+ if self .t_replace_counter % self .t_replace_iter == 0 :
155+ self .sess .run ([tf .assign (t , e ) for t , e in zip (self .t_params , self .e_params )])
156+ self .t_replace_counter += 1
157+
158+
159+ class Memory (object ):
160+ def __init__ (self , capacity , dims ):
161+ self .capacity = capacity
162+ self .data = np .zeros ((capacity , dims ))
163+ self .pointer = 0
164+
165+ def store_transition (self , s , a , r , s_ ):
166+ transition = np .hstack ((s , a , [r ], s_ ))
167+ index = self .pointer % self .capacity # replace the old memory with new memory
168+ self .data [index , :] = transition
169+ self .pointer += 1
170+
171+ def sample (self , n ):
172+ assert self .pointer >= self .capacity , 'Memory has not been fulfilled'
173+ indices = np .random .choice (self .capacity , size = n )
174+ return self .data [indices , :]
175+
176+
177+ sess = tf .Session ()
178+
179+ # Create actor and critic.
180+ actor = Actor (sess , ACTION_DIM , ACTION_BOUND [1 ], LR_A , REPLACE_ITER_A )
181+ critic = Critic (sess , STATE_DIM , ACTION_DIM , LR_C , GAMMA , REPLACE_ITER_C , actor .a_ )
182+ actor .add_grad_to_graph (critic .a_grads )
183+
184+ M = Memory (MEMORY_CAPACITY , dims = 2 * STATE_DIM + ACTION_DIM + 1 )
185+
186+ saver = tf .train .Saver ()
187+ path = './' + MODE [n_model ]
188+
189+ if LOAD :
190+ saver .restore (sess , tf .train .latest_checkpoint (path ))
191+ else :
192+ sess .run (tf .global_variables_initializer ())
193+
194+
195+ def train ():
196+ var = 2. # control exploration
197+
198+ for ep in range (MAX_EPISODES ):
199+ s = env .reset ()
200+ ep_reward = 0
201+
202+ for t in range (MAX_EP_STEPS ):
203+ # while True:
204+ if RENDER :
205+ env .render ()
206+
207+ # Added exploration noise
208+ a = actor .choose_action (s )
209+ a = np .clip (np .random .normal (a , var ), * ACTION_BOUND ) # add randomness to action selection for exploration
210+ s_ , r , done = env .step (a )
211+ M .store_transition (s , a , r , s_ )
212+
213+ if M .pointer > MEMORY_CAPACITY :
214+ var = max ([var * .99995 , VAR_MIN ]) # decay the action randomness
215+ b_M = M .sample (BATCH_SIZE )
216+ b_s = b_M [:, :STATE_DIM ]
217+ b_a = b_M [:, STATE_DIM : STATE_DIM + ACTION_DIM ]
218+ b_r = b_M [:, - STATE_DIM - 1 : - STATE_DIM ]
219+ b_s_ = b_M [:, - STATE_DIM :]
220+
221+ critic .learn (b_s , b_a , b_r , b_s_ )
222+ actor .learn (b_s , b_a )
223+
224+ s = s_
225+ ep_reward += r
226+
227+ if t == MAX_EP_STEPS - 1 or done :
228+ # if done:
229+ result = '| done' if done else '| ----'
230+ print ('Ep:' , ep ,
231+ result ,
232+ '| R: %i' % int (ep_reward ),
233+ '| Explore: %.2f' % var ,
234+ )
235+ break
236+
237+ if os .path .isdir (path ): shutil .rmtree (path )
238+ os .mkdir (path )
239+ ckpt_path = os .path .join ('./' + MODE [n_model ], 'DDPG.ckpt' )
240+ save_path = saver .save (sess , ckpt_path , write_meta_graph = False )
241+ print ("\n Save Model %s\n " % save_path )
242+
243+
244+ def eval ():
245+ env .set_fps (30 )
246+ s = env .reset ()
247+ while True :
248+ if RENDER :
249+ env .render ()
250+ a = actor .choose_action (s )
251+ s_ , r , done = env .step (a )
252+ s = s_
253+
254+ if __name__ == '__main__' :
255+ if LOAD :
256+ eval ()
257+ else :
258+ train ()
0 commit comments