policy is ok
This commit is contained in:
commit
f08fa36b46
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# 已忽略包含查询文件的默认文件夹
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/TowFootBot-rust.iml" filepath="$PROJECT_DIR$/.idea/TowFootBot-rust.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "TowFootBot-rust"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
[dependencies]
|
||||
tract = "0.23"
|
||||
tract-metal = "0.23"
|
||||
ndarray = "0.16"
|
||||
anyhow = "1.0"
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,31 @@
|
|||
mod policy;
|
||||
use anyhow::{Context, Result};
|
||||
// fn main() -> Result<()> {
|
||||
// //循环
|
||||
// for _ in 0..10 {
|
||||
// let action = policy::policy([0.0; 36])?;
|
||||
// println!("模型输出: {action:?}");
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
const N: u32 = 1000;
|
||||
let mut total_infer = std::time::Duration::ZERO;
|
||||
|
||||
for _ in 0..N {
|
||||
let start = Instant::now();
|
||||
let action = policy::policy([0.0; 36])?;
|
||||
total_infer += start.elapsed();
|
||||
println!("模型输出: {action:?}");
|
||||
}
|
||||
|
||||
println!(
|
||||
"平均耗时: {:?}",
|
||||
total_infer / N
|
||||
);
|
||||
println!("采样次数: {N}");
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
use std::path::Path;
|
||||
use anyhow::{Context, Result, ensure};
|
||||
use tract::prelude::*;
|
||||
|
||||
/// 运行策略模型:输入 36 维观测值,返回 8 维动作输出。
|
||||
///
|
||||
/// - 每次调用都会重新加载并准备模型(简单、无状态,方便一行调用)。
|
||||
/// - 模型路径固定为 `CARGO_MANIFEST_DIR/model/policy.onnx`。
|
||||
/// - 使用 Metal 运行时。
|
||||
pub fn policy(observation: [f32; 36]) -> Result<[f32; 8]> {
|
||||
let model_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("model/policy.onnx");
|
||||
|
||||
// 加载模型
|
||||
let model = tract::onnx()?
|
||||
.load(&model_path)
|
||||
.with_context(|| format!("failed to load ONNX model at {}", model_path.display()))?
|
||||
.into_model()?;
|
||||
|
||||
// 校验输入数量与类型
|
||||
ensure!(model.input_count()? == 1, "policy model must have exactly one input");
|
||||
let input_fact = model.input_fact(0)?;
|
||||
ensure!(
|
||||
input_fact.datum_type()? == DatumType::F32,
|
||||
"policy model input must be f32, got {:?}",
|
||||
input_fact.datum_type()?
|
||||
);
|
||||
|
||||
// 读取固定输入形状
|
||||
let input_shape = (0..input_fact.rank()?)
|
||||
.map(|axis| {
|
||||
let dim = input_fact
|
||||
.dim(axis)?
|
||||
.to_int64()
|
||||
.with_context(|| format!("input dimension {axis} must be fixed"))?;
|
||||
usize::try_from(dim)
|
||||
.with_context(|| format!("input dimension {axis} must be non-negative"))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// 校验 shape 与 observation 长度匹配
|
||||
let input_len: usize = input_shape.iter().product();
|
||||
ensure!(
|
||||
input_len == observation.len(),
|
||||
"expected {input_len} observation values for input shape {input_shape:?}, got {}",
|
||||
observation.len()
|
||||
);
|
||||
|
||||
// 构造输入张量并推理
|
||||
let input_tensor = Tensor::from_slice(&input_shape, &observation)?;
|
||||
let runtime = tract::runtime_for_name("metal")?;
|
||||
let runnable = runtime.prepare(model)?;
|
||||
let outputs = runnable.run([input_tensor])?;
|
||||
|
||||
// 取第一个输出并转成 [f32; 8]
|
||||
let output = outputs
|
||||
.first()
|
||||
.context("policy model produced no output")?;
|
||||
let values = output.as_slice::<f32>()?;
|
||||
ensure!(
|
||||
values.len() == 8,
|
||||
"expected 8 output values, got {}",
|
||||
values.len()
|
||||
);
|
||||
|
||||
let mut result = [0.0f32; 8];
|
||||
result.copy_from_slice(values);
|
||||
Ok(result)
|
||||
}
|
||||
Loading…
Reference in New Issue