Vladprime commited on
Commit
795b5aa
·
verified ·
1 Parent(s): 26b4a6f

Add trained PPO RND policy, original configuration and separate ONNX evaluation

Browse files
Pyramids-checkpoint.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac7abd37e208346febbe4fca29a787d3dfd1868c28ee8803d4f3a7bc1346dd28
3
+ size 1120546
Pyramids.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:81dfbe80127803d88c0b0b8c40897ecfd770b11bf48060f9bd7696ed614b46ba
3
+ size 162254
README.md CHANGED
@@ -1,3 +1,29 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ tags:
4
+ - reinforcement-learning
5
+ - ml-agents
6
+ - ML-Agents-Pyramids
7
+ - deep-rl-class
8
+ model-index:
9
+ - name: Pyramids
10
+ results:
11
+ - task:
12
+ type: reinforcement-learning
13
+ name: Reinforcement Learning
14
+ dataset:
15
+ name: ML-Agents-Pyramids
16
+ type: ML-Agents-Pyramids
17
+ metrics:
18
+ - type: mean_reward
19
+ name: mean_reward
20
+ value: -0.8986 +/- 0.4869
21
  ---
22
+
23
+ # Pyramids
24
+
25
+ Trained from random initialization for Vlad Kolomiiets (`Vladprime`) using the official Hugging Face Deep RL Course Unity environment and Unity ML-Agents 1.1.0. No pretrained weights were used. This is an initial training run; it is not claimed to have converged. Units 5 and 7 require publishing a trained model without a reward threshold.
26
+
27
+ Training: ppo, 30000 configured environment steps, seed 20261101. Export: genuine ML-Agents ONNX plus PyTorch checkpoint and trainer configuration. Separate ONNX evaluation process: seed 1000000; 48 completed agent episodes, mean -0.8986, standard deviation 0.4869. Original environment, action and observation spaces were retained. See results.json for individual returns and evaluation limitations.
28
+
29
+ The .onnx file is compatible with the course Unity browser viewer. Training/evaluation code is in train-unity.py; the exact run configuration is config.yaml.
SHA256SUMS.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "README.md": "3e2fc56c64aad22bfacc52d9480856ab248ac3de672589f400d2fdf0f2147ce5",
3
+ "results.json": "60301238ffa276b419413d8812575e0421f147616959c62b811b7c67a66bec14",
4
+ "events.out.tfevents.1793538415.e5108cd25e8e.9652.0": "ed6c12e017457fa171dbf49e9ff02e50e0debc778649b26c9b57fb1a948e6fd3",
5
+ "Pyramids-checkpoint.pt": "ac7abd37e208346febbe4fca29a787d3dfd1868c28ee8803d4f3a7bc1346dd28",
6
+ "Pyramids.onnx": "81dfbe80127803d88c0b0b8c40897ecfd770b11bf48060f9bd7696ed614b46ba",
7
+ "config.yaml": "a37a966fef2cf29346be2b1dd97532923df5bee61d54594dbcc2155f3665983c",
8
+ "train-unity.py": "dce2bd5169df6422af51eecf3ef243b4af8aa08444152598fefa600859462b59"
9
+ }
config.yaml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ behaviors:
2
+ Pyramids:
3
+ trainer_type: ppo
4
+ hyperparameters:
5
+ batch_size: 128
6
+ buffer_size: 2048
7
+ learning_rate: 0.0003
8
+ beta: 0.01
9
+ epsilon: 0.2
10
+ lambd: 0.95
11
+ num_epoch: 3
12
+ learning_rate_schedule: linear
13
+ network_settings:
14
+ normalize: false
15
+ hidden_units: 128
16
+ num_layers: 2
17
+ vis_encode_type: simple
18
+ reward_signals:
19
+ extrinsic:
20
+ gamma: 0.99
21
+ strength: 1.0
22
+ rnd:
23
+ gamma: 0.99
24
+ strength: 0.01
25
+ network_settings:
26
+ hidden_units: 64
27
+ num_layers: 3
28
+ learning_rate: 0.0001
29
+ keep_checkpoints: 2
30
+ max_steps: 30000
31
+ time_horizon: 128
32
+ summary_freq: 2000
33
+ checkpoint_interval: 10000
events.out.tfevents.1793538415.e5108cd25e8e.9652.0 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ed6c12e017457fa171dbf49e9ff02e50e0debc778649b26c9b57fb1a948e6fd3
3
+ size 7315
results.json ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mean_reward": -0.8986040989945346,
3
+ "std_reward": 0.48686846265775247,
4
+ "mean_minus_std": -1.3854725616522872,
5
+ "n_eval_agent_episodes": 48,
6
+ "episode_rewards": [
7
+ -0.9999999310821295,
8
+ -0.9999999310821295,
9
+ -0.9999999310821295,
10
+ -0.9999999310821295,
11
+ -0.9999999310821295,
12
+ -0.9999999310821295,
13
+ -0.9999999310821295,
14
+ -0.9999999310821295,
15
+ -0.9999999310821295,
16
+ -0.9999999310821295,
17
+ -0.9999999310821295,
18
+ -0.9999999310821295,
19
+ -0.9999999310821295,
20
+ -0.9999999310821295,
21
+ -0.9999999310821295,
22
+ -0.9999999310821295,
23
+ 1.3160000471398234,
24
+ -0.9999999310821295,
25
+ -0.9999999310821295,
26
+ -0.9999999310821295,
27
+ -0.9999999310821295,
28
+ -0.9999999310821295,
29
+ -0.9999999310821295,
30
+ -0.9999999310821295,
31
+ -0.9999999310821295,
32
+ -0.9999999310821295,
33
+ -0.9999999310821295,
34
+ -0.9999999310821295,
35
+ -0.9999999310821295,
36
+ -0.9999999310821295,
37
+ -0.9999999310821295,
38
+ -0.9999999310821295,
39
+ 1.5510000309441239,
40
+ -0.9999999311257852,
41
+ -0.9999999310821295,
42
+ -0.9999999310821295,
43
+ -0.9999999310821295,
44
+ -0.9999999310821295,
45
+ -0.9999999310821295,
46
+ -0.9999999310821295,
47
+ -0.9999999310821295,
48
+ -0.9999999310821295,
49
+ -0.9999999310821295,
50
+ -0.9999999310821295,
51
+ -0.9999999310821295,
52
+ -0.9999999310821295,
53
+ -0.9999999310821295,
54
+ -0.9999999310821295
55
+ ],
56
+ "records": [
57
+ {
58
+ "behavior": "Pyramids?team=0",
59
+ "agent_id": 0,
60
+ "reward": -0.9999999310821295,
61
+ "interrupted": true
62
+ },
63
+ {
64
+ "behavior": "Pyramids?team=0",
65
+ "agent_id": 1,
66
+ "reward": -0.9999999310821295,
67
+ "interrupted": true
68
+ },
69
+ {
70
+ "behavior": "Pyramids?team=0",
71
+ "agent_id": 2,
72
+ "reward": -0.9999999310821295,
73
+ "interrupted": true
74
+ },
75
+ {
76
+ "behavior": "Pyramids?team=0",
77
+ "agent_id": 3,
78
+ "reward": -0.9999999310821295,
79
+ "interrupted": true
80
+ },
81
+ {
82
+ "behavior": "Pyramids?team=0",
83
+ "agent_id": 4,
84
+ "reward": -0.9999999310821295,
85
+ "interrupted": true
86
+ },
87
+ {
88
+ "behavior": "Pyramids?team=0",
89
+ "agent_id": 5,
90
+ "reward": -0.9999999310821295,
91
+ "interrupted": true
92
+ },
93
+ {
94
+ "behavior": "Pyramids?team=0",
95
+ "agent_id": 6,
96
+ "reward": -0.9999999310821295,
97
+ "interrupted": true
98
+ },
99
+ {
100
+ "behavior": "Pyramids?team=0",
101
+ "agent_id": 7,
102
+ "reward": -0.9999999310821295,
103
+ "interrupted": true
104
+ },
105
+ {
106
+ "behavior": "Pyramids?team=0",
107
+ "agent_id": 8,
108
+ "reward": -0.9999999310821295,
109
+ "interrupted": true
110
+ },
111
+ {
112
+ "behavior": "Pyramids?team=0",
113
+ "agent_id": 9,
114
+ "reward": -0.9999999310821295,
115
+ "interrupted": true
116
+ },
117
+ {
118
+ "behavior": "Pyramids?team=0",
119
+ "agent_id": 10,
120
+ "reward": -0.9999999310821295,
121
+ "interrupted": true
122
+ },
123
+ {
124
+ "behavior": "Pyramids?team=0",
125
+ "agent_id": 11,
126
+ "reward": -0.9999999310821295,
127
+ "interrupted": true
128
+ },
129
+ {
130
+ "behavior": "Pyramids?team=0",
131
+ "agent_id": 12,
132
+ "reward": -0.9999999310821295,
133
+ "interrupted": true
134
+ },
135
+ {
136
+ "behavior": "Pyramids?team=0",
137
+ "agent_id": 13,
138
+ "reward": -0.9999999310821295,
139
+ "interrupted": true
140
+ },
141
+ {
142
+ "behavior": "Pyramids?team=0",
143
+ "agent_id": 14,
144
+ "reward": -0.9999999310821295,
145
+ "interrupted": true
146
+ },
147
+ {
148
+ "behavior": "Pyramids?team=0",
149
+ "agent_id": 15,
150
+ "reward": -0.9999999310821295,
151
+ "interrupted": true
152
+ },
153
+ {
154
+ "behavior": "Pyramids?team=0",
155
+ "agent_id": 10,
156
+ "reward": 1.3160000471398234,
157
+ "interrupted": false
158
+ },
159
+ {
160
+ "behavior": "Pyramids?team=0",
161
+ "agent_id": 0,
162
+ "reward": -0.9999999310821295,
163
+ "interrupted": true
164
+ },
165
+ {
166
+ "behavior": "Pyramids?team=0",
167
+ "agent_id": 1,
168
+ "reward": -0.9999999310821295,
169
+ "interrupted": true
170
+ },
171
+ {
172
+ "behavior": "Pyramids?team=0",
173
+ "agent_id": 2,
174
+ "reward": -0.9999999310821295,
175
+ "interrupted": true
176
+ },
177
+ {
178
+ "behavior": "Pyramids?team=0",
179
+ "agent_id": 3,
180
+ "reward": -0.9999999310821295,
181
+ "interrupted": true
182
+ },
183
+ {
184
+ "behavior": "Pyramids?team=0",
185
+ "agent_id": 4,
186
+ "reward": -0.9999999310821295,
187
+ "interrupted": true
188
+ },
189
+ {
190
+ "behavior": "Pyramids?team=0",
191
+ "agent_id": 5,
192
+ "reward": -0.9999999310821295,
193
+ "interrupted": true
194
+ },
195
+ {
196
+ "behavior": "Pyramids?team=0",
197
+ "agent_id": 6,
198
+ "reward": -0.9999999310821295,
199
+ "interrupted": true
200
+ },
201
+ {
202
+ "behavior": "Pyramids?team=0",
203
+ "agent_id": 7,
204
+ "reward": -0.9999999310821295,
205
+ "interrupted": true
206
+ },
207
+ {
208
+ "behavior": "Pyramids?team=0",
209
+ "agent_id": 8,
210
+ "reward": -0.9999999310821295,
211
+ "interrupted": true
212
+ },
213
+ {
214
+ "behavior": "Pyramids?team=0",
215
+ "agent_id": 9,
216
+ "reward": -0.9999999310821295,
217
+ "interrupted": true
218
+ },
219
+ {
220
+ "behavior": "Pyramids?team=0",
221
+ "agent_id": 11,
222
+ "reward": -0.9999999310821295,
223
+ "interrupted": true
224
+ },
225
+ {
226
+ "behavior": "Pyramids?team=0",
227
+ "agent_id": 12,
228
+ "reward": -0.9999999310821295,
229
+ "interrupted": true
230
+ },
231
+ {
232
+ "behavior": "Pyramids?team=0",
233
+ "agent_id": 13,
234
+ "reward": -0.9999999310821295,
235
+ "interrupted": true
236
+ },
237
+ {
238
+ "behavior": "Pyramids?team=0",
239
+ "agent_id": 14,
240
+ "reward": -0.9999999310821295,
241
+ "interrupted": true
242
+ },
243
+ {
244
+ "behavior": "Pyramids?team=0",
245
+ "agent_id": 15,
246
+ "reward": -0.9999999310821295,
247
+ "interrupted": true
248
+ },
249
+ {
250
+ "behavior": "Pyramids?team=0",
251
+ "agent_id": 12,
252
+ "reward": 1.5510000309441239,
253
+ "interrupted": false
254
+ },
255
+ {
256
+ "behavior": "Pyramids?team=0",
257
+ "agent_id": 10,
258
+ "reward": -0.9999999311257852,
259
+ "interrupted": true
260
+ },
261
+ {
262
+ "behavior": "Pyramids?team=0",
263
+ "agent_id": 0,
264
+ "reward": -0.9999999310821295,
265
+ "interrupted": true
266
+ },
267
+ {
268
+ "behavior": "Pyramids?team=0",
269
+ "agent_id": 1,
270
+ "reward": -0.9999999310821295,
271
+ "interrupted": true
272
+ },
273
+ {
274
+ "behavior": "Pyramids?team=0",
275
+ "agent_id": 2,
276
+ "reward": -0.9999999310821295,
277
+ "interrupted": true
278
+ },
279
+ {
280
+ "behavior": "Pyramids?team=0",
281
+ "agent_id": 3,
282
+ "reward": -0.9999999310821295,
283
+ "interrupted": true
284
+ },
285
+ {
286
+ "behavior": "Pyramids?team=0",
287
+ "agent_id": 4,
288
+ "reward": -0.9999999310821295,
289
+ "interrupted": true
290
+ },
291
+ {
292
+ "behavior": "Pyramids?team=0",
293
+ "agent_id": 5,
294
+ "reward": -0.9999999310821295,
295
+ "interrupted": true
296
+ },
297
+ {
298
+ "behavior": "Pyramids?team=0",
299
+ "agent_id": 6,
300
+ "reward": -0.9999999310821295,
301
+ "interrupted": true
302
+ },
303
+ {
304
+ "behavior": "Pyramids?team=0",
305
+ "agent_id": 7,
306
+ "reward": -0.9999999310821295,
307
+ "interrupted": true
308
+ },
309
+ {
310
+ "behavior": "Pyramids?team=0",
311
+ "agent_id": 8,
312
+ "reward": -0.9999999310821295,
313
+ "interrupted": true
314
+ },
315
+ {
316
+ "behavior": "Pyramids?team=0",
317
+ "agent_id": 9,
318
+ "reward": -0.9999999310821295,
319
+ "interrupted": true
320
+ },
321
+ {
322
+ "behavior": "Pyramids?team=0",
323
+ "agent_id": 11,
324
+ "reward": -0.9999999310821295,
325
+ "interrupted": true
326
+ },
327
+ {
328
+ "behavior": "Pyramids?team=0",
329
+ "agent_id": 13,
330
+ "reward": -0.9999999310821295,
331
+ "interrupted": true
332
+ },
333
+ {
334
+ "behavior": "Pyramids?team=0",
335
+ "agent_id": 14,
336
+ "reward": -0.9999999310821295,
337
+ "interrupted": true
338
+ },
339
+ {
340
+ "behavior": "Pyramids?team=0",
341
+ "agent_id": 15,
342
+ "reward": -0.9999999310821295,
343
+ "interrupted": true
344
+ }
345
+ ],
346
+ "evaluation_seed": 1000000,
347
+ "eval_datetime": "2026-11-01T13:09:03.627062+00:00",
348
+ "evaluation_kind": "separate Unity process, ONNX policy, completed agent episodes (soccer episodes within a match are correlated)"
349
+ }
train-unity.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Own from-scratch course ML-Agents training, export, independent ONNX evaluation.
2
+ Run inside the compatible Linux environment prepared by colab-setup.py.
3
+ """
4
+ from pathlib import Path
5
+ from datetime import datetime,timezone
6
+ import os,sys,json,subprocess,zipfile,urllib.request,hashlib,shutil,time
7
+ import numpy as np
8
+ import yaml
9
+ ROOT=Path('/content/vlad-deep-rl-unity');ROOT.mkdir(exist_ok=True)
10
+ os.environ['OMP_NUM_THREADS']='1';os.environ['MKL_NUM_THREADS']='1'
11
+ SEED=20261101
12
+
13
+ def download(url,target):
14
+ print('Downloading official course environment',target.name,flush=True)
15
+ urllib.request.urlretrieve(url,target)
16
+ def unzip(path,target):
17
+ target.mkdir(exist_ok=True)
18
+ with zipfile.ZipFile(path) as z:
19
+ for item in z.infolist():
20
+ if not (target/item.filename).resolve().is_relative_to(target.resolve()):raise ValueError('Unsafe zip member')
21
+ z.extractall(target)
22
+ def evaluate_onnx(model,executable,output):
23
+ from mlagents_envs.environment import UnityEnvironment
24
+ from mlagents_envs.base_env import ActionTuple
25
+ from mlagents_envs.side_channel.engine_configuration_channel import EngineConfigurationChannel
26
+ import onnxruntime as ort
27
+ opts=ort.SessionOptions();opts.intra_op_num_threads=1;opts.inter_op_num_threads=1
28
+ session=ort.InferenceSession(str(model),sess_options=opts,providers=['CPUExecutionProvider'])
29
+ print('ONNX inputs',[(i.name,i.shape) for i in session.get_inputs()],flush=True)
30
+ channel=EngineConfigurationChannel();channel.set_configuration_parameters(time_scale=20)
31
+ env=UnityEnvironment(file_name=str(executable),seed=1000000,no_graphics=True,side_channels=[channel],worker_id=10,timeout_wait=120)
32
+ totals={};records=[]
33
+ try:
34
+ env.reset()
35
+ for iteration in range(30000):
36
+ for behavior in env.behavior_specs:
37
+ decision,terminal=env.get_steps(behavior)
38
+ for agent_id in terminal.agent_id:
39
+ step=terminal[agent_id];key=(behavior,int(agent_id));total=totals.pop(key,0.0)+float(step.reward)+float(step.group_reward)
40
+ records.append({'behavior':behavior,'agent_id':int(agent_id),'reward':total,'interrupted':bool(step.interrupted)})
41
+ for agent_id in decision.agent_id:
42
+ step=decision[agent_id];key=(behavior,int(agent_id));totals[key]=totals.get(key,0.0)+float(step.reward)+float(step.group_reward)
43
+ if len(decision):
44
+ inputs={}
45
+ for spec in session.get_inputs():
46
+ if spec.name.startswith('obs_'):inputs[spec.name]=decision.obs[int(spec.name.split('_')[-1])].astype(np.float32)
47
+ elif spec.name=='action_masks':
48
+ inputs[spec.name]=np.concatenate([1-m.astype(np.float32) for m in decision.action_mask],axis=1)
49
+ else:raise ValueError('Unexpected ONNX input '+spec.name)
50
+ values=session.run(None,inputs);values={spec.name:value for spec,value in zip(session.get_outputs(),values)}
51
+ action=ActionTuple()
52
+ if 'continuous_actions' in values:action.add_continuous(values['continuous_actions'].astype(np.float32))
53
+ if 'discrete_actions' in values:action.add_discrete(values['discrete_actions'].astype(np.int32))
54
+ env.set_actions(behavior,action)
55
+ if len(records)>=40:break
56
+ env.step()
57
+ finally:env.close()
58
+ if not records:raise RuntimeError('Independent evaluation completed no episodes')
59
+ rewards=[r['reward'] for r in records];mean=float(np.mean(rewards));std=float(np.std(rewards))
60
+ result={'mean_reward':mean,'std_reward':std,'mean_minus_std':mean-std,'n_eval_agent_episodes':len(rewards),'episode_rewards':rewards,'records':records,'evaluation_seed':1000000,'eval_datetime':datetime.now(timezone.utc).isoformat(),'evaluation_kind':'separate Unity process, ONNX policy, completed agent episodes (soccer episodes within a match are correlated)'}
61
+ output.write_text(json.dumps(result,indent=2));print('EVALUATED',model.name,mean,std,flush=True);return result
62
+
63
+ def card(folder,name,env_tag,result,config):
64
+ meta={'license':'apache-2.0','tags':['reinforcement-learning','ml-agents',env_tag,'deep-rl-class'],'model-index':[{'name':name,'results':[{'task':{'type':'reinforcement-learning','name':'Reinforcement Learning'},'dataset':{'name':env_tag,'type':env_tag},'metrics':[{'type':'mean_reward','name':'mean_reward','value':f"{result['mean_reward']:.4f} +/- {result['std_reward']:.4f}"}]}]}]}
65
+ text='---\n'+yaml.safe_dump(meta,sort_keys=False)+'---\n\n# '+name+'\n\n'
66
+ text+='Trained from random initialization for Vlad Kolomiiets (`Vladprime`) using the official Hugging Face Deep RL Course Unity environment and Unity ML-Agents 1.1.0. No pretrained weights were used. This is an initial training run; it is not claimed to have converged. Units 5 and 7 require publishing a trained model without a reward threshold.\n\n'
67
+ text+=f"Training: {config['trainer_type']}, {config['max_steps']} configured environment steps, seed {SEED}. Export: genuine ML-Agents ONNX plus PyTorch checkpoint and trainer configuration. Separate ONNX evaluation process: seed 1000000; {result['n_eval_agent_episodes']} completed agent episodes, mean {result['mean_reward']:.4f}, standard deviation {result['std_reward']:.4f}. Original environment, action and observation spaces were retained. See results.json for individual returns and evaluation limitations.\n\n"
68
+ if 'Soccer' in env_tag:text+='Offline MA-POCA self-play training and local evaluation only. No ranked AI-vs-AI challenge result is claimed; the course online leaderboard is unavailable. Player episodes within a soccer match are correlated.\n\n'
69
+ text+='The .onnx file is compatible with the course Unity browser viewer. Training/evaluation code is in train-unity.py; the exact run configuration is config.yaml.\n'
70
+ (folder/'README.md').write_text(text)
71
+ (folder/'SHA256SUMS.json').write_text(json.dumps({str(p.relative_to(folder)):hashlib.sha256(p.read_bytes()).hexdigest() for p in folder.rglob('*') if p.is_file() and p.name!='SHA256SUMS.json'},indent=2))
72
+
73
+ def main():
74
+ sources=[('SnowballTarget','https://github.com/huggingface/Snowball-Target/raw/main/SnowballTarget.zip','SnowballTarget/SnowballTarget.x86_64','SnowballTarget.yaml','ML-Agents-SnowballTarget'),('Pyramids','https://huggingface.co/spaces/unity/ML-Agents-Pyramids/resolve/main/Pyramids.zip','Pyramids/Pyramids','PyramidsRND-local.yaml','ML-Agents-Pyramids'),('SoccerTwos','gdrive:1KuqBKYiXiIcU4kNMqEzhgypuFP5_45CL','SoccerTwos.x86_64','SoccerTwos-local.yaml','ML-Agents-SoccerTwos')]
75
+ results=[]
76
+ for name,url,relative,config_name,env_tag in sources:
77
+ zip_path=ROOT/(name+'.zip')
78
+ if not zip_path.exists():
79
+ if url.startswith('gdrive:'):
80
+ import gdown;gdown.download(id=url.split(':')[1],output=str(zip_path),quiet=False)
81
+ else:download(url,zip_path)
82
+ target=ROOT/('env-'+name);unzip(zip_path,target);executable=target/relative;executable.chmod(executable.stat().st_mode|0o111)
83
+ config_path=ROOT/config_name;config=yaml.safe_load(config_path.read_text());behavior=next(iter(config['behaviors'].values()));run_id='vlad-'+name
84
+ command=[str(Path(sys.executable).parent/'mlagents-learn'),str(config_path),'--env='+str(executable),'--run-id='+run_id,'--no-graphics','--seed='+str(SEED),'--torch-device=cpu','--results-dir='+str(ROOT/'training')]
85
+ print('TRAINING',name,' '.join(command),flush=True)
86
+ subprocess.run(command,check=True,env={**os.environ,'OMP_NUM_THREADS':'1','MKL_NUM_THREADS':'1'})
87
+ trained=ROOT/'training'/run_id;model=list(trained.rglob('*.onnx'))
88
+ # Final exported model is at the run root; step checkpoints live in behavior subdirectories.
89
+ model=next((p for p in model if p.parent==trained),model[-1])
90
+ output=ROOT/('publish-'+name);output.mkdir(exist_ok=True)
91
+ shutil.copy2(model,output/(name+'.onnx'))
92
+ for p in trained.rglob('*.pt'):
93
+ if p.name=='checkpoint.pt':shutil.copy2(p,output/(name+'-checkpoint.pt'));break
94
+ shutil.copy2(config_path,output/'config.yaml');shutil.copy2(__file__,output/'train-unity.py')
95
+ logs=list(trained.rglob('events.out.tfevents*'))
96
+ if logs:shutil.copy2(logs[0],output/logs[0].name)
97
+ result=evaluate_onnx(output/(name+'.onnx'),executable,output/'results.json');card(output,name,env_tag,result,behavior)
98
+ shutil.make_archive(str(ROOT/('publish-'+name)),'zip',output)
99
+ results.append({'name':name,**{k:result[k] for k in ['mean_reward','std_reward','mean_minus_std','n_eval_agent_episodes']}})
100
+ (ROOT/'summary.json').write_text(json.dumps(results,indent=2));print('ALL_UNITY_TRAINING_COMPLETE',json.dumps(results),flush=True)
101
+ if __name__=='__main__':main()