dsh-eval-guard 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/neural-pendulum/SPEC.md +470 -0
- package/assets/neural-pendulum/TASK.md +360 -0
- package/assets/neural-pendulum/hidden/test_infra.cpp +631 -0
- package/assets/neural-pendulum/include/nn/nn.hpp +88 -0
- package/assets/neural-pendulum/sim.cpp +126 -0
- package/assets/neural-pendulum/sim_eval +0 -0
- package/assets/neural-pendulum/workspace.zip +0 -0
- package/eval/neural-pendulum.py +15 -0
- package/lib/client/index.js +41 -4
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +454 -60
- package/neural-cifar-eval/README.md +57 -0
- package/neural-cifar-eval/cifar_cache.py +201 -0
- package/neural-cifar-eval/common.py +67 -0
- package/neural-cifar-eval/fetch_cifar.py +31 -0
- package/neural-cifar-eval/hidden/.gitkeep +1 -0
- package/neural-cifar-eval/ops_eval.py +502 -0
- package/neural-cifar-eval/run_eval.py +208 -0
- package/neural-pendulum-eval/run_eval.py +302 -0
- package/neural-pendulum-eval/sim_eval +0 -0
- package/package.json +4 -2
- package/eval/__pycache__/common.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-cifar.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-fp32.cpython-310.pyc +0 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Neural-Pendulum:从零神经网络基础设施与双驱动三阶摆控制
|
|
2
|
+
|
|
3
|
+
## 任务目标
|
|
4
|
+
|
|
5
|
+
从零实现一套纯 C++17、仅 CPU、fp32 的神经网络基础设施,并用它训练一个神经网络控制器,控制预编译的双驱动三节摆。
|
|
6
|
+
|
|
7
|
+
目标:
|
|
8
|
+
|
|
9
|
+
- 从三杆全部向下的固定初始状态起摆
|
|
10
|
+
- 保持三根杆全部向上至少 t_tgt = 10.0 秒
|
|
11
|
+
- 同时保证神经网络基础设施通过固定头文件契约并通过隐藏测试
|
|
12
|
+
|
|
13
|
+
允许使用 PyTorch 做开发阶段的自查和数值对照。最终提交源码中不得出现 torch,评测环境不提供 Python/torch。
|
|
14
|
+
|
|
15
|
+
## 环境
|
|
16
|
+
|
|
17
|
+
工作区提供预编译仿真器:
|
|
18
|
+
|
|
19
|
+
~~~
|
|
20
|
+
tools/sim
|
|
21
|
+
~~~
|
|
22
|
+
|
|
23
|
+
不提供仿真器源码和物理参数。
|
|
24
|
+
|
|
25
|
+
### 初始状态
|
|
26
|
+
|
|
27
|
+
训练时每次 reset:
|
|
28
|
+
|
|
29
|
+
- 三根杆接近全向下
|
|
30
|
+
- 角度以全向下为中心,只加小范围随机噪声
|
|
31
|
+
- 不添加固定角度偏差
|
|
32
|
+
- 带小范围随机初始角速度
|
|
33
|
+
|
|
34
|
+
评测时:
|
|
35
|
+
|
|
36
|
+
- 使用固定初始状态
|
|
37
|
+
- 三个固定角度互不相同
|
|
38
|
+
- 三个固定角度的绝对值也互不相同
|
|
39
|
+
- 初始角速度为 0
|
|
40
|
+
- 不加任何随机扰动
|
|
41
|
+
|
|
42
|
+
### 驱动结构
|
|
43
|
+
|
|
44
|
+
~~~text
|
|
45
|
+
joint 1:驱动
|
|
46
|
+
joint 2:被动
|
|
47
|
+
joint 3:驱动
|
|
48
|
+
~~~
|
|
49
|
+
|
|
50
|
+
第一关节和第三关节各有一个归一化力矩输入。
|
|
51
|
+
|
|
52
|
+
### 观测
|
|
53
|
+
|
|
54
|
+
控制器每一步只获得三个关节角度:
|
|
55
|
+
|
|
56
|
+
~~~text
|
|
57
|
+
a_i = wrap_to_pi(theta_i - pi) i = 1,2,3
|
|
58
|
+
obs = [a1, a2, a3] (rad)
|
|
59
|
+
~~~
|
|
60
|
+
|
|
61
|
+
即 3 维观测,单位 rad,不除以 pi。
|
|
62
|
+
|
|
63
|
+
- theta_i 是第 i 根杆的绝对角度
|
|
64
|
+
- a_i 是相对竖直向上的角度误差
|
|
65
|
+
- 不提供角速度
|
|
66
|
+
- 不提供第三杆末端位置
|
|
67
|
+
- 不提供杆长、质量、惯量等物理参数
|
|
68
|
+
|
|
69
|
+
控制器的内部结构和训练方法由你自行设计。
|
|
70
|
+
|
|
71
|
+
### 动作
|
|
72
|
+
|
|
73
|
+
控制器输出两个归一化力矩:
|
|
74
|
+
|
|
75
|
+
~~~text
|
|
76
|
+
[u1, u3] ∈ [-1, 1]^2
|
|
77
|
+
~~~
|
|
78
|
+
|
|
79
|
+
分别作用于第一关节和第三关节。第二关节始终无驱动。
|
|
80
|
+
|
|
81
|
+
非有限值、超范围或格式错误会判为控制器失败。
|
|
82
|
+
|
|
83
|
+
### 控制与仿真
|
|
84
|
+
|
|
85
|
+
~~~
|
|
86
|
+
控制频率 = 100 Hz
|
|
87
|
+
控制周期 = 0.01 s
|
|
88
|
+
最大仿真时间 = 30.0 s
|
|
89
|
+
t_tgt = 10.0 s
|
|
90
|
+
全向上容差 = 每根杆与竖直方向夹角 <= 0.05 rad
|
|
91
|
+
~~~
|
|
92
|
+
|
|
93
|
+
评测会计算:
|
|
94
|
+
|
|
95
|
+
~~~
|
|
96
|
+
t_can = 三根杆同时处于全向上容差内的最长连续时间
|
|
97
|
+
~~~
|
|
98
|
+
|
|
99
|
+
当:
|
|
100
|
+
|
|
101
|
+
~~~
|
|
102
|
+
t_can >= t_tgt
|
|
103
|
+
且基础设施测试全部通过
|
|
104
|
+
~~~
|
|
105
|
+
|
|
106
|
+
任务完成,计时停止。
|
|
107
|
+
|
|
108
|
+
## 训练用仿真接口
|
|
109
|
+
|
|
110
|
+
tools/sim 使用 JSONL 协议。
|
|
111
|
+
|
|
112
|
+
输入:
|
|
113
|
+
|
|
114
|
+
~~~json
|
|
115
|
+
{"cmd":"reset"}
|
|
116
|
+
{"cmd":"step","torque":[0.5,-0.5]}
|
|
117
|
+
~~~
|
|
118
|
+
|
|
119
|
+
输出:
|
|
120
|
+
|
|
121
|
+
~~~json
|
|
122
|
+
{"obs":[3 floats]}
|
|
123
|
+
~~~
|
|
124
|
+
|
|
125
|
+
每个 episode 最多 3000 步(30.0 s)。
|
|
126
|
+
|
|
127
|
+
达到最大步数后再发送 step:
|
|
128
|
+
|
|
129
|
+
~~~json
|
|
130
|
+
{"error":"episode_finished"}
|
|
131
|
+
~~~
|
|
132
|
+
|
|
133
|
+
此时不返回新观测,也不会继续推进仿真。
|
|
134
|
+
必须 reset 后才能开始新 episode;reset 前的 step 都返回该错误。
|
|
135
|
+
|
|
136
|
+
可以反复 reset / step 进行数据采集、模型训练和自测。
|
|
137
|
+
|
|
138
|
+
环境只返回状态,不提供 reward、loss、cost 或 done 信号。
|
|
139
|
+
训练信号由你自行构造。
|
|
140
|
+
|
|
141
|
+
## 交付内容
|
|
142
|
+
|
|
143
|
+
只提交源码,不提交编译产物。
|
|
144
|
+
|
|
145
|
+
源码根目录必须支持:
|
|
146
|
+
|
|
147
|
+
~~~
|
|
148
|
+
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
|
149
|
+
cmake --build build -j4
|
|
150
|
+
~~~
|
|
151
|
+
|
|
152
|
+
必须产出:
|
|
153
|
+
|
|
154
|
+
~~~
|
|
155
|
+
build/libnn.a
|
|
156
|
+
build/control
|
|
157
|
+
~~~
|
|
158
|
+
|
|
159
|
+
### 1. 基础设施入口
|
|
160
|
+
|
|
161
|
+
基础设施实现放在 `src/nn/*.cpp`,由 CMake 构建为 `build/libnn.a`;公开头文件 `include/nn/nn.hpp` 是固定 API 契约,不得修改声明或语义。
|
|
162
|
+
|
|
163
|
+
评测侧会独立编译隐藏测试并链接 `build/libnn.a`,不使用你写的 `nn_selftest` 作为验证依据。`build/nn_selftest` 可选,仅用于你自己的开发自测。
|
|
164
|
+
|
|
165
|
+
必须包含的基础设施:
|
|
166
|
+
|
|
167
|
+
- fp32 tensor,形状检查与广播
|
|
168
|
+
- elementwise add/sub/mul/div
|
|
169
|
+
- matmul / linear
|
|
170
|
+
- relu / softmax
|
|
171
|
+
- layernorm
|
|
172
|
+
- conv2d,支持 stride/padding/dilation/groups
|
|
173
|
+
- MSE
|
|
174
|
+
- matmul/linear/relu/layernorm/conv2d/MSE 反向
|
|
175
|
+
- SGD momentum
|
|
176
|
+
- AdamW
|
|
177
|
+
- 模型保存/加载
|
|
178
|
+
- 线程池
|
|
179
|
+
|
|
180
|
+
占位符或空实现会被判为基础设施错误。
|
|
181
|
+
|
|
182
|
+
隐藏测试由评测侧注入,使用固定种子和独立数据,不复制到工作区。
|
|
183
|
+
|
|
184
|
+
### 2. 控制器入口
|
|
185
|
+
|
|
186
|
+
build/control 是一个常驻进程,通过 stdin/stdout 使用 JSONL 通信。
|
|
187
|
+
|
|
188
|
+
输入:
|
|
189
|
+
|
|
190
|
+
~~~json
|
|
191
|
+
{"type":"reset"}
|
|
192
|
+
{"type":"step","step":0,"state":[3 floats]}
|
|
193
|
+
~~~
|
|
194
|
+
|
|
195
|
+
输出:
|
|
196
|
+
|
|
197
|
+
~~~json
|
|
198
|
+
{"type":"ready"}
|
|
199
|
+
{"type":"action","torque":[0.5,-0.5]}
|
|
200
|
+
~~~
|
|
201
|
+
|
|
202
|
+
规则:
|
|
203
|
+
|
|
204
|
+
- 每次评测启动一个新进程
|
|
205
|
+
- 先收到 reset,必须回复 ready
|
|
206
|
+
- 每个 step 必须在 100 ms 内回复
|
|
207
|
+
- 控制器可以保存内部历史状态
|
|
208
|
+
- 崩溃、超时、非法输出会判为控制器失败
|
|
209
|
+
|
|
210
|
+
## 提交与测试
|
|
211
|
+
|
|
212
|
+
使用宿主工具:
|
|
213
|
+
|
|
214
|
+
~~~text
|
|
215
|
+
eval_submit
|
|
216
|
+
eval_test
|
|
217
|
+
~~~
|
|
218
|
+
|
|
219
|
+
### eval_submit
|
|
220
|
+
|
|
221
|
+
把当前工作区源码快照提交到宿主侧不可读目录。每次提交独立保留,不覆盖旧提交。提交本身不改变分数。
|
|
222
|
+
|
|
223
|
+
### eval_test
|
|
224
|
+
|
|
225
|
+
由宿主对最新提交快照进行构建和隐藏仿真评估,返回:
|
|
226
|
+
|
|
227
|
+
~~~text
|
|
228
|
+
stage
|
|
229
|
+
t_can
|
|
230
|
+
completed
|
|
231
|
+
error
|
|
232
|
+
~~~
|
|
233
|
+
|
|
234
|
+
只有 eval_test 会更新分数。第一次 eval_test 之前必须先 eval_submit,否则 stage = no_submission。
|
|
235
|
+
|
|
236
|
+
阶段枚举:
|
|
237
|
+
|
|
238
|
+
~~~text
|
|
239
|
+
no_submission
|
|
240
|
+
compile
|
|
241
|
+
infra
|
|
242
|
+
controller
|
|
243
|
+
simulation
|
|
244
|
+
scoring
|
|
245
|
+
completed
|
|
246
|
+
busy
|
|
247
|
+
~~~
|
|
248
|
+
|
|
249
|
+
最终排行分数不会返回给你,只用于赛后排名。
|
|
250
|
+
|
|
251
|
+
## 完成条件
|
|
252
|
+
|
|
253
|
+
当测试返回:
|
|
254
|
+
|
|
255
|
+
~~~
|
|
256
|
+
stage = completed
|
|
257
|
+
t_can >= 10.0
|
|
258
|
+
~~~
|
|
259
|
+
|
|
260
|
+
即任务完成。
|
|
261
|
+
|
|
262
|
+
完成后:
|
|
263
|
+
|
|
264
|
+
- 立即停止修改
|
|
265
|
+
- 立即总结你的实现
|
|
266
|
+
- 之后的提交和测试请求都会被拒绝
|
|
267
|
+
|
|
268
|
+
## 约束
|
|
269
|
+
|
|
270
|
+
- 只允许 C++17 + CMake + C++ 标准库
|
|
271
|
+
- 仅 CPU,fp32
|
|
272
|
+
- 提交源码中不得出现 torch
|
|
273
|
+
- 评测环境无 Python/torch
|
|
274
|
+
- 无网络
|
|
275
|
+
- 不得修改仿真器或公开头文件 `include/nn/nn.hpp`
|
|
276
|
+
- 不得提交编译产物
|
|
277
|
+
- 赛后人工审核:控制器必须是神经网络,且必须实际调用你实现的神经网络基础设施;手写控制律、查表、固定轨迹或外部依赖会被判无效
|
|
278
|
+
|
|
279
|
+
## 优化目标
|
|
280
|
+
|
|
281
|
+
从接近全向下的初始状态起摆,使三根杆全部进入竖直向上容差,并尽可能长时间保持。
|
|
282
|
+
|
|
283
|
+
这是一个控制目标,不是固定损失函数。环境不提供 reward/loss;你需要自己决定训练信号、损失、奖励或优化方式。
|
|
284
|
+
|
|
285
|
+
## 评分规则
|
|
286
|
+
|
|
287
|
+
任务从会话开始时刻计时。
|
|
288
|
+
|
|
289
|
+
### 测试请求与分数
|
|
290
|
+
|
|
291
|
+
提交源码本身不改变分数。
|
|
292
|
+
|
|
293
|
+
只有申请测试会更新当前分数:
|
|
294
|
+
|
|
295
|
+
~~~
|
|
296
|
+
无效测试 / 编译失败 / 基础设施失败 / 控制器失败 / 仿真失败 / 无提交:
|
|
297
|
+
score(t) = -1
|
|
298
|
+
|
|
299
|
+
有效测试:
|
|
300
|
+
score(t) = (min(t_can, t_tgt) - t_tgt) / t_tgt
|
|
301
|
+
~~~
|
|
302
|
+
|
|
303
|
+
其中:
|
|
304
|
+
|
|
305
|
+
~~~
|
|
306
|
+
t_tgt = 10.0 s
|
|
307
|
+
score(t) 的范围是 [-1, 0]
|
|
308
|
+
t_can = 0 时 score = -1
|
|
309
|
+
t_can >= t_tgt 时 score = 0
|
|
310
|
+
~~~
|
|
311
|
+
|
|
312
|
+
分数从测试请求时刻开始生效,直到下一次测试请求。
|
|
313
|
+
|
|
314
|
+
第一次测试请求之前,score = -1。
|
|
315
|
+
|
|
316
|
+
### 最终分数
|
|
317
|
+
|
|
318
|
+
最终分数是时间积分,不除以总时长:
|
|
319
|
+
|
|
320
|
+
~~~
|
|
321
|
+
final = integral_0^T_done score(t) dt
|
|
322
|
+
~~~
|
|
323
|
+
|
|
324
|
+
T_done 是第一次返回 completed 的测试请求时间。
|
|
325
|
+
|
|
326
|
+
因此:
|
|
327
|
+
|
|
328
|
+
- 越早达到完成条件,负分区间越短,最终分数越高
|
|
329
|
+
- 拖得越久,负分区间越长
|
|
330
|
+
- 完成后停止积分
|
|
331
|
+
- 未完成不参与最终排名
|
|
332
|
+
|
|
333
|
+
### 完成时
|
|
334
|
+
|
|
335
|
+
当测试返回 completed 时:
|
|
336
|
+
|
|
337
|
+
- 当前 score 固定为 0
|
|
338
|
+
- 时间积分立即停止
|
|
339
|
+
- 之后的提交和测试全部拒绝
|
|
340
|
+
- 不会再有新的分数变化
|
|
341
|
+
|
|
342
|
+
### 测试结果与最终分数
|
|
343
|
+
|
|
344
|
+
测试结果会返回:
|
|
345
|
+
|
|
346
|
+
- stage
|
|
347
|
+
- t_can
|
|
348
|
+
- completed
|
|
349
|
+
- error
|
|
350
|
+
|
|
351
|
+
最终排行分数不会返回给你,只用于赛后排名。
|
|
352
|
+
|
|
353
|
+
## 建议工作顺序
|
|
354
|
+
|
|
355
|
+
1. 阅读 `include/nn/nn.hpp` 契约与 tools/sim 协议
|
|
356
|
+
2. 先实现最小可用的 tensor/算子/反向/优化器
|
|
357
|
+
3. 用自测和 `include/nn/nn.hpp` 契约检查基础设施
|
|
358
|
+
4. 用 tools/sim 采集数据并训练控制器
|
|
359
|
+
5. 反复提交和测试,优先把 t_can 提升到 10 秒
|
|
360
|
+
6. 完成后立即总结
|