අටාරිකඩාවැටීම සමඟ PPO අත්හදා බැලීම

මෙමඅත්හදා බැලීම OpenAI Gym හි ප්රොක්සිමල් ප්රතිපත්ති ප්රශස්තිකරණය (PPO) නියෝජිත අටාරි බ්රේක් ක්රීඩාව පුහුණු කරයි. කාර්යක්ෂමව සාම්පල ලබා ගැනීම සඳහා එය බහු ක්රියාවලීන්හි ක්රීඩා පරිසරයන් ක්රියාත්මක කරයි.

Open In Colab View Run

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,

⚙️නියැදි දත්ත සමඟ ආකෘතිය පුහුණු කිරීම සඳහා එපොච් ගණන. අත්හදා බැලීම ක්රියාත්මක වන අතරතුර ඔබට මෙය වෙනස් කළ හැකිය. Example

365        'epochs': IntDynamicHyperParam(8),

සේවකක්රියාවලි ගණන

367        'n_workers': 8,

තනියාවත්කාලීන කිරීම සඳහා එක් එක් ක්රියාවලිය මත ක්රියාත්මක කිරීමට පියවර ගණන

369        'worker_steps': 128,

කුඩාකණ්ඩායම් ගණන

371        'batches': 4,

⚙️අගය අහිමි සංගුණකය. අත්හදා බැලීම ක්රියාත්මක වන අතරතුර ඔබට මෙය වෙනස් කළ හැකිය. Example

375        'value_loss_coef': FloatDynamicHyperParam(0.5),

⚙️එන්ට්රොපි ප්රසාද සංගුණකය. අත්හදා බැලීම ක්රියාත්මක වන අතරතුර ඔබට මෙය වෙනස් කළ හැකිය. Example

379        'entropy_bonus_coef': FloatDynamicHyperParam(0.01),

⚙️ක්ලිප් පරාසය.

381        'clip_range': FloatDynamicHyperParam(0.1),

අත්හදාබැලීම ක්රියාත්මක වන අතරතුර ඔබට මෙය වෙනස් කළ හැකිය. Example ⚙️ ඉගෙනුම් අනුපාතය.

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()