මෙමඅත්හදා බැලීම OpenAI Gym හි ප්රොක්සිමල් ප්රතිපත්ති ප්රශස්තිකරණය (PPO) නියෝජිත අටාරි බ්රේක් ක්රීඩාව පුහුණු කරයි. කාර්යක්ෂමව සාම්පල ලබා ගැනීම සඳහා එය බහු ක්රියාවලීන්හි ක්රීඩා පරිසරයන් ක්රියාත්මක කරයි.
16from typing import Dict
17
18import numpy as np
19import torch
20from torch import nn
21from torch import optim
22from torch.distributions import Categorical
23
24from labml import monit, tracker, logger, experiment
25from labml.configs import FloatDynamicHyperParam, IntDynamicHyperParam
26from labml_helpers.module import Module
27from labml_nn.rl.game import Worker
28from labml_nn.rl.ppo import ClippedPPOLoss, ClippedValueFunctionLoss
29from labml_nn.rl.ppo.gae import GAE
උපාංගයතෝරන්න
32if torch.cuda.is_available():
33 device = torch.device("cuda:0")
34else:
35 device = torch.device("cpu")
38class Model(Module):
43 def __init__(self):
44 super().__init__()
පළමුකැටි ගැසුණු ස්තරය 84x84 රාමුවක් ගෙන 20x20 රාමුවක් නිපදවයි
48 self.conv1 = nn.Conv2d(in_channels=4, out_channels=32, kernel_size=8, stride=4)
දෙවනකැටි ගැසුණු ස්තරය 20x20 රාමුවක් ගෙන 9x9 රාමුවක් නිපදවයි
52 self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=4, stride=2)
තෙවනකැටි ගැසුණු ස්තරය 9x9 රාමුවක් ගෙන 7x7 රාමුවක් නිපදවයි
56 self.conv3 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1)
සම්පුර්ණයෙන්මසම්බන්ධිත තට්ටුවක් පැතලි රාමුව තෙවන කැටි ගැසුණු ස්ථරයෙන් ගෙන යන අතර විශේෂාංග 512 ක් ප්රතිදානය කරයි
61 self.lin = nn.Linear(in_features=7 * 7 * 64, out_features=512)
සඳහාපිවිසුම් ලබා ගැනීම සඳහා පූර්ණ සම්බන්ධිත තට්ටුවක්
64 self.pi_logits = nn.Linear(in_features=512, out_features=4)
අගයශ්රිතය ලබා ගැනීම සඳහා පූර්ණ සම්බන්ධිත තට්ටුවක්
67 self.value = nn.Linear(in_features=512, out_features=1)
70 self.activation = nn.ReLU()
72 def forward(self, obs: torch.Tensor):
73 h = self.activation(self.conv1(obs))
74 h = self.activation(self.conv2(h))
75 h = self.activation(self.conv3(h))
76 h = h.reshape((-1, 7 * 7 * 64))
77
78 h = self.activation(self.lin(h))
79
80 pi = Categorical(logits=self.pi_logits(h))
81 value = self.value(h).reshape(-1)
82
83 return pi, value
සිට [0, 255]
පරිමාණ නිරීක්ෂණ [0, 1]
86def obs_to_torch(obs: np.ndarray) -> torch.Tensor:
88 return torch.tensor(obs, dtype=torch.float32, device=device) / 255.
91class Trainer:
96 def __init__(self, *,
97 updates: int, epochs: IntDynamicHyperParam,
98 n_workers: int, worker_steps: int, batches: int,
99 value_loss_coef: FloatDynamicHyperParam,
100 entropy_bonus_coef: FloatDynamicHyperParam,
101 clip_range: FloatDynamicHyperParam,
102 learning_rate: FloatDynamicHyperParam,
103 ):
යාවත්කාලීනගණන
107 self.updates = updates
නියැදිදත්ත සමඟ ආකෘතිය පුහුණු කිරීම සඳහා එපොච් ගණන
109 self.epochs = epochs
සේවකක්රියාවලි ගණන
111 self.n_workers = n_workers
තනියාවත්කාලීන කිරීම සඳහා එක් එක් ක්රියාවලිය මත ක්රියාත්මක කිරීමට පියවර ගණන
113 self.worker_steps = worker_steps
කුඩාකණ්ඩායම් ගණන
115 self.batches = batches
තනියාවත්කාලීන කිරීම සඳහා මුළු සාම්පල ගණන
117 self.batch_size = self.n_workers * self.worker_steps
කුඩාකණ්ඩායමක ප්රමාණය
119 self.mini_batch_size = self.batch_size // self.batches
120 assert (self.batch_size % self.batches == 0)
අගයඅහිමි සංගුණකය
123 self.value_loss_coef = value_loss_coef
එන්ට්රොපිප්රසාද සංගුණකය
125 self.entropy_bonus_coef = entropy_bonus_coef
ක්ලිපින්පරාසය
128 self.clip_range = clip_range
ඉගෙනුම්අනුපාතය
130 self.learning_rate = learning_rate
කම්කරුවන්නිර්මාණය
135 self.workers = [Worker(47 + i) for i in range(self.n_workers)]
නිරීක්ෂණසඳහා ආතතීන් ආරම්භ කරන්න
138 self.obs = np.zeros((self.n_workers, 4, 84, 84), dtype=np.uint8)
139 for worker in self.workers:
140 worker.child.send(("reset", None))
141 for i, worker in enumerate(self.workers):
142 self.obs[i] = worker.child.recv()
ආකෘතිය
145 self.model = Model().to(device)
ප්රශස්තකරණය
148 self.optimizer = optim.Adam(self.model.parameters(), lr=2.5e-4)
GAEසමඟ සහ
151 self.gae = GAE(self.n_workers, self.worker_steps, 0.99, 0.95)
PPOපාඩුව
154 self.ppo_loss = ClippedPPOLoss()
අගයනැතිවීම
157 self.value_loss = ClippedValueFunctionLoss()
159 def sample(self) -> Dict[str, torch.Tensor]:
164 rewards = np.zeros((self.n_workers, self.worker_steps), dtype=np.float32)
165 actions = np.zeros((self.n_workers, self.worker_steps), dtype=np.int32)
166 done = np.zeros((self.n_workers, self.worker_steps), dtype=np.bool)
167 obs = np.zeros((self.n_workers, self.worker_steps, 4, 84, 84), dtype=np.uint8)
168 log_pis = np.zeros((self.n_workers, self.worker_steps), dtype=np.float32)
169 values = np.zeros((self.n_workers, self.worker_steps + 1), dtype=np.float32)
170
171 with torch.no_grad():
සෑම worker_steps
සේවකයෙකුගේම නියැදිය
173 for t in range(self.worker_steps):
self.obs
එක් එක් සේවකයාගෙන් අවසාන නිරීක්ෂණය නිරීක්ෂණය කරයි, එය ඊළඟ ක්රියාව නියැදි කිරීම සඳහා ආකෘතියට ආදානය වේ
176 obs[:, t] = self.obs
එක්එක් සේවකයා සඳහා නියැදි ක්රියා; මෙය ප්රමාණයේ අරා නැවත ලබා දෙයි n_workers
179 pi, v = self.model(obs_to_torch(self.obs))
180 values[:, t] = v.cpu().numpy()
181 a = pi.sample()
182 actions[:, t] = a.cpu().numpy()
183 log_pis[:, t] = pi.log_prob(a).cpu().numpy()
එක්එක් සේවකයා මත නියැදි ක්රියා ක්රියාත්මක
186 for w, worker in enumerate(self.workers):
187 worker.child.send(("step", actions[w, t]))
188
189 for w, worker in enumerate(self.workers):
ක්රියාවන්ක්රියාත්මක කිරීමෙන් පසු ප්රති results ල ලබා ගන්න
191 self.obs[w], rewards[w, t], done[w, t], info = worker.child.recv()
කථාංගතොරතුරු එකතු කරන්න, කථාංගයක් අවසන් වුවහොත් එය ලබා ගත හැකිය; මෙයට කථාංගයේ සම්පූර්ණ විපාකය සහ දිග ඇතුළත් වේ - එය ක්රියාත්මක වන ආකාරය Game
බැලීමට බලන්න.
196 if info:
197 tracker.add('reward', info['reward'])
198 tracker.add('length', info['length'])
අවසානපියවරෙන් පසු වටිනාකම ලබා ගන්න
201 _, v = self.model(obs_to_torch(self.obs))
202 values[:, self.worker_steps] = v.cpu().numpy()
වාසිගණනය කරන්න
205 advantages = self.gae(done, rewards, values)
208 samples = {
209 'obs': obs,
210 'actions': actions,
211 'values': values[:, :-1],
212 'log_pis': log_pis,
213 'advantages': advantages
214 }
සාම්පලදැනට [workers, time_step]
වගුවේ ඇත, අපි පුහුණුව සඳහා එය සමතලා කළ යුතුය
218 samples_flat = {}
219 for k, v in samples.items():
220 v = v.reshape(v.shape[0] * v.shape[1], *v.shape[2:])
221 if k == 'obs':
222 samples_flat[k] = obs_to_torch(v)
223 else:
224 samples_flat[k] = torch.tensor(v, device=device)
225
226 return samples_flat
228 def train(self, samples: Dict[str, torch.Tensor]):
එයවැඩි එපොච් සංඛ්යාවක් සමඟ වේගයෙන් ඉගෙන ගනී, නමුත් ටිකක් අස්ථායී වේ; එනම්, සාමාන්ය කථාංග විපාකය කාලයත් සමඟ ඒකාකාරී ලෙස වැඩි නොවේ. ක්ලිපින් පරාසය අඩු කිරීමෙන් එය විසඳිය හැකිය.
238 for _ in range(self.epochs()):
එක්එක් ඊපෝච් සඳහා කලවම් කරන්න
240 indexes = torch.randperm(self.batch_size)
එක්එක් කුඩා කණ්ඩායම සඳහා
243 for start in range(0, self.batch_size, self.mini_batch_size):
කුඩාකණ්ඩායම ලබා ගන්න
245 end = start + self.mini_batch_size
246 mini_batch_indexes = indexes[start: end]
247 mini_batch = {}
248 for k, v in samples.items():
249 mini_batch[k] = v[mini_batch_indexes]
දුම්රිය
252 loss = self._calc_loss(mini_batch)
ඉගෙනුම්අනුපාතය සකසන්න
255 for pg in self.optimizer.param_groups:
256 pg['lr'] = self.learning_rate()
කලින්ගණනය කරන ලද අනුක්රමික ශුන්ය කිරීම
258 self.optimizer.zero_grad()
අනුක්රමිකගණනය කරන්න
260 loss.backward()
ක්ලිප්අනුක්රමික
262 torch.nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=0.5)
අනුක්රමිකමත පදනම්ව පරාමිතීන් යාවත්කාලීන කරන්න
264 self.optimizer.step()
266 @staticmethod
267 def _normalize(adv: torch.Tensor):
269 return (adv - adv.mean()) / (adv.std() + 1e-8)
271 def _calc_loss(self, samples: Dict[str, torch.Tensor]) -> torch.Tensor:
සිට නියැදිය ප්රතිලාභ
277 sampled_return = samples['values'] + samples['advantages']
, කොහෙන්ද? වාසි ලබා ඇත . ගණනය කිරීම සඳහා පහත ප්රධාන පන්තියේ නියැදි ශ්රිතය වෙත යොමු වන්න .
283 sampled_normalized_advantage = self._normalize(samples['advantages'])
නියැදිනිරීක්ෂණ ලබා ගැනීමට ආකෘතියට පෝෂණය වන අතර ; අපි නිරීක්ෂණ රාජ්ය ලෙස සලකමු
287 pi, value = self.model(samples['obs'])
, ක්රියා වලින් නියැලී ඇත
290 log_pi = pi.log_prob(samples['actions'])
ප්රතිපත්තිඅලාභය ගණනය කරන්න
293 policy_loss = self.ppo_loss(log_pi, samples['log_pis'], sampled_normalized_advantage, self.clip_range())
299 entropy_bonus = pi.entropy()
300 entropy_bonus = entropy_bonus.mean()
අගයශ්රිතය අහිමි ගණනය
303 value_loss = self.value_loss(value, samples['values'], sampled_return, self.clip_range())
308 loss = (policy_loss
309 + self.value_loss_coef() * value_loss
310 - self.entropy_bonus_coef() * entropy_bonus)
අධීක්ෂණයසඳහා
313 approx_kl_divergence = .5 * ((samples['log_pis'] - log_pi) ** 2).mean()
ට්රැකර්වෙත එකතු කරන්න
316 tracker.add({'policy_reward': -policy_loss,
317 'value_loss': value_loss,
318 'entropy_bonus': entropy_bonus,
319 'kl_div': approx_kl_divergence,
320 'clip_fraction': self.ppo_loss.clip_fraction})
321
322 return loss
324 def run_training_loop(self):
අවසන්100 කථාංග තොරතුරු
330 tracker.set_queue('reward', 100, True)
331 tracker.set_queue('length', 100, True)
332
333 for update in monit.loop(self.updates):
වත්මන්ප්රතිපත්තිය සමඟ නියැදිය
335 samples = self.sample()
ආකෘතියපුහුණු කරන්න
338 self.train(samples)
ලුහුබැඳඇති දර්ශක සුරකින්න.
341 tracker.save()
වරින්වර තිරයට නව රේඛාවක් එක් කරන්න
343 if (update + 1) % 1_000 == 0:
344 logger.log()
346 def destroy(self):
351 for worker in self.workers:
352 worker.child.send(("close", None))
355def main():
අත්හදාබැලීම සාදන්න
357 experiment.create(name='ppo')
වින්යාසකිරීම්
359 configs = {
යාවත්කාලීනගණන
361 'updates': 10000,
⚙️නියැදි දත්ත සමඟ ආකෘතිය පුහුණු කිරීම සඳහා එපොච් ගණන. අත්හදා බැලීම ක්රියාත්මක වන අතරතුර ඔබට මෙය වෙනස් කළ හැකිය.
365 'epochs': IntDynamicHyperParam(8),
සේවකක්රියාවලි ගණන
367 'n_workers': 8,
තනියාවත්කාලීන කිරීම සඳහා එක් එක් ක්රියාවලිය මත ක්රියාත්මක කිරීමට පියවර ගණන
369 'worker_steps': 128,
කුඩාකණ්ඩායම් ගණන
371 'batches': 4,
375 'value_loss_coef': FloatDynamicHyperParam(0.5),
379 'entropy_bonus_coef': FloatDynamicHyperParam(0.01),
⚙️ක්ලිප් පරාසය.
381 'clip_range': FloatDynamicHyperParam(0.1),
385 'learning_rate': FloatDynamicHyperParam(1e-3, (0, 1e-3)),
386 }
387
388 experiment.configs(configs)
පුහුණුකරුආරම්භ කරන්න
391 m = Trainer(**configs)
අත්හදාබැලීම ධාවනය කර අධීක්ෂණය කරන්න
394 with experiment.start():
395 m.run_training_loop()
කම්කරුවන්නවත්වන්න
397 m.destroy()
401if __name__ == "__main__":
402 main()