adapt gym 5history
This commit is contained in:
@@ -59,8 +59,6 @@ class BpuInferLibPolicy:
|
||||
"""Default fast backend: direct C++ DNN API via ctypes."""
|
||||
|
||||
backend_name = "cpp_dnn_api_x5"
|
||||
input_shape = (1, 1, 1, 450)
|
||||
output_shape = (1, 12, 1, 1)
|
||||
|
||||
def __init__(self, model_path, priority=0, bpu_cores=(0,), cpp_lib=DEFAULT_CPP_LIB):
|
||||
self.model_path = Path(model_path).expanduser().resolve()
|
||||
@@ -94,6 +92,10 @@ class BpuInferLibPolicy:
|
||||
self._lib.rlgym_bpu_infer.restype = ctypes.c_int
|
||||
self._lib.rlgym_bpu_destroy.argtypes = [ctypes.c_void_p]
|
||||
self._lib.rlgym_bpu_destroy.restype = None
|
||||
self._lib.rlgym_bpu_input_floats.argtypes = [ctypes.c_void_p]
|
||||
self._lib.rlgym_bpu_input_floats.restype = ctypes.c_int
|
||||
self._lib.rlgym_bpu_output_floats.argtypes = [ctypes.c_void_p]
|
||||
self._lib.rlgym_bpu_output_floats.restype = ctypes.c_int
|
||||
self._lib.rlgym_bpu_version.argtypes = []
|
||||
self._lib.rlgym_bpu_version.restype = ctypes.c_char_p
|
||||
|
||||
@@ -107,7 +109,13 @@ class BpuInferLibPolicy:
|
||||
)
|
||||
if not self._handle:
|
||||
raise RuntimeError(err.value.decode("utf-8", errors="replace"))
|
||||
self._output = np.empty(12, dtype=np.float32)
|
||||
self.input_size = int(self._lib.rlgym_bpu_input_floats(self._handle))
|
||||
self.output_size = int(self._lib.rlgym_bpu_output_floats(self._handle))
|
||||
if self.input_size <= 0 or self.output_size <= 0:
|
||||
raise RuntimeError("invalid BPU tensor sizes reported by runtime")
|
||||
self.input_shape = (1, 1, 1, self.input_size)
|
||||
self.output_shape = (1, self.output_size, 1, 1)
|
||||
self._output = np.empty(self.output_size, dtype=np.float32)
|
||||
self._output_ptr = self._output.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
|
||||
self._err = ctypes.create_string_buffer(1024)
|
||||
|
||||
@@ -131,8 +139,8 @@ class BpuInferLibPolicy:
|
||||
|
||||
def __call__(self, flat_input):
|
||||
arr = np.asarray(flat_input, dtype=np.float32)
|
||||
if arr.size != 450:
|
||||
raise ValueError(f"BPU policy input has {arr.size} values, expected 450")
|
||||
if arr.size != self.input_size:
|
||||
raise ValueError(f"BPU policy input has {arr.size} values, expected {self.input_size}")
|
||||
input_flat = np.ascontiguousarray(arr.reshape(-1), dtype=np.float32)
|
||||
rc = self._lib.rlgym_bpu_infer(
|
||||
self._handle,
|
||||
@@ -172,6 +180,9 @@ class BpuInferLibPythonPolicy:
|
||||
self.priority = int(priority)
|
||||
self.bpu_cores = tuple(int(core) for core in bpu_cores)
|
||||
self.suppress_runtime_output = bool(suppress_runtime_output)
|
||||
self.input_size = 450
|
||||
self.input_shape = (1, 1, 1, self.input_size)
|
||||
self.output_shape = (1, 12, 1, 1)
|
||||
with suppress_c_output(self.suppress_runtime_output):
|
||||
self.infer = Infer(False)
|
||||
loaded = self.infer.load_model(str(self.model_path))
|
||||
@@ -185,8 +196,8 @@ class BpuInferLibPythonPolicy:
|
||||
|
||||
def __call__(self, flat_input):
|
||||
arr = np.asarray(flat_input, dtype=np.float32)
|
||||
if arr.size != 450:
|
||||
raise ValueError(f"BPU policy input has {arr.size} values, expected 450")
|
||||
if arr.size != self.input_size:
|
||||
raise ValueError(f"BPU policy input has {arr.size} values, expected {self.input_size}")
|
||||
input_4d = np.ascontiguousarray(arr.reshape(self.input_shape), dtype=np.float32)
|
||||
with suppress_c_output(self.suppress_runtime_output):
|
||||
copied = self.infer.read_numpy_arr_float32(input_4d, 0)
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
extern "C" {
|
||||
void *rlgym_bpu_create(const char *model_path, int bpu_core, int priority,
|
||||
char *err, int err_len);
|
||||
int rlgym_bpu_infer(void *handle, const float *input450, float *output12, char *err,
|
||||
int rlgym_bpu_infer(void *handle, const float *input, float *output, char *err,
|
||||
int err_len);
|
||||
int rlgym_bpu_input_floats(void *handle);
|
||||
int rlgym_bpu_output_floats(void *handle);
|
||||
void rlgym_bpu_destroy(void *handle);
|
||||
}
|
||||
|
||||
@@ -54,12 +56,6 @@ int main(int argc, char **argv) {
|
||||
if (argc > 2) input = argv[2];
|
||||
if (argc > 3) repeat = std::atoi(argv[3]);
|
||||
|
||||
std::vector<float> obs;
|
||||
if (!read_f32_file(input, &obs) || obs.size() != 450) {
|
||||
std::cerr << "failed to read 450 float32 input: " << input << "\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
char err[1024] = {};
|
||||
void *handle = rlgym_bpu_create(model, 1, 0, err, sizeof(err));
|
||||
if (handle == nullptr) {
|
||||
@@ -67,20 +63,37 @@ int main(int argc, char **argv) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
float out[12] = {};
|
||||
if (rlgym_bpu_infer(handle, obs.data(), out, err, sizeof(err)) != 0) {
|
||||
const int input_floats = rlgym_bpu_input_floats(handle);
|
||||
const int output_floats = rlgym_bpu_output_floats(handle);
|
||||
if (input_floats <= 0 || output_floats <= 0) {
|
||||
std::cerr << "invalid tensor sizes from BPU runtime\n";
|
||||
rlgym_bpu_destroy(handle);
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::vector<float> obs;
|
||||
if (!read_f32_file(input, &obs) || static_cast<int>(obs.size()) != input_floats) {
|
||||
std::cerr << "failed to read " << input_floats << " float32 input: " << input << "\n";
|
||||
rlgym_bpu_destroy(handle);
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::vector<float> out(static_cast<size_t>(output_floats), 0.0f);
|
||||
if (rlgym_bpu_infer(handle, obs.data(), out.data(), err, sizeof(err)) != 0) {
|
||||
std::cerr << err << "\n";
|
||||
rlgym_bpu_destroy(handle);
|
||||
return 4;
|
||||
}
|
||||
float max_diff = 0.0f;
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
max_diff = std::max(max_diff, std::fabs(out[i] - kReference[i]));
|
||||
if (input_floats == 450 && output_floats == 12) {
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
max_diff = std::max(max_diff, std::fabs(out[static_cast<size_t>(i)] - kReference[i]));
|
||||
}
|
||||
}
|
||||
|
||||
const auto t0 = std::chrono::steady_clock::now();
|
||||
for (int i = 0; i < repeat; ++i) {
|
||||
if (rlgym_bpu_infer(handle, obs.data(), out, err, sizeof(err)) != 0) {
|
||||
if (rlgym_bpu_infer(handle, obs.data(), out.data(), err, sizeof(err)) != 0) {
|
||||
std::cerr << err << "\n";
|
||||
rlgym_bpu_destroy(handle);
|
||||
return 5;
|
||||
@@ -90,10 +103,13 @@ int main(int argc, char **argv) {
|
||||
const double elapsed_ms =
|
||||
std::chrono::duration<double, std::milli>(t1 - t0).count();
|
||||
|
||||
std::cout << "reference_max_abs_diff " << max_diff << "\n";
|
||||
std::cout << "input_floats=" << input_floats << " output_floats=" << output_floats << "\n";
|
||||
if (input_floats == 450 && output_floats == 12) {
|
||||
std::cout << "reference_max_abs_diff " << max_diff << "\n";
|
||||
}
|
||||
std::cout << "repeat=" << repeat << " cpp_avg_ms=" << (elapsed_ms / repeat) << "\n";
|
||||
std::cout << "action0=" << out[0] << " action_max_abs="
|
||||
<< *std::max_element(out, out + 12, [](float a, float b) {
|
||||
<< *std::max_element(out.begin(), out.end(), [](float a, float b) {
|
||||
return std::fabs(a) < std::fabs(b);
|
||||
})
|
||||
<< "\n";
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kInputFloats = 450;
|
||||
constexpr int kOutputFloats = 12;
|
||||
|
||||
void set_error(char *err, int err_len, const std::string &msg) {
|
||||
@@ -88,10 +87,10 @@ class BpuDnnPolicy {
|
||||
check_dnn(hbDNNGetOutputTensorProperties(&output_tensors_[0].properties, dnn_handle_, 0),
|
||||
"hbDNNGetOutputTensorProperties");
|
||||
|
||||
validate_tensor(input_tensors_[0].properties, kInputFloats, HB_DNN_TENSOR_TYPE_F32,
|
||||
"input");
|
||||
validate_tensor(output_tensors_[0].properties, kOutputFloats, HB_DNN_TENSOR_TYPE_F32,
|
||||
"output");
|
||||
input_floats_ = element_count(input_tensors_[0].properties.validShape);
|
||||
output_floats_ = element_count(output_tensors_[0].properties.validShape);
|
||||
validate_tensor(input_tensors_[0].properties, HB_DNN_TENSOR_TYPE_F32, "input");
|
||||
validate_tensor(output_tensors_[0].properties, HB_DNN_TENSOR_TYPE_F32, "output");
|
||||
|
||||
alloc_tensor_mem(input_tensors_[0]);
|
||||
alloc_tensor_mem(output_tensors_[0]);
|
||||
@@ -112,7 +111,7 @@ class BpuDnnPolicy {
|
||||
}
|
||||
|
||||
auto &input_mem = input_tensors_[0].sysMem[0];
|
||||
std::memcpy(input_mem.virAddr, input, sizeof(float) * kInputFloats);
|
||||
std::memcpy(input_mem.virAddr, input, sizeof(float) * input_floats_);
|
||||
int code = hbSysFlushMem(&input_mem, HB_SYS_MEM_CACHE_CLEAN);
|
||||
if (code != 0) {
|
||||
throw std::runtime_error(dnn_error("hbSysFlushMem(input)", code));
|
||||
@@ -137,18 +136,15 @@ class BpuDnnPolicy {
|
||||
if (code != 0) {
|
||||
throw std::runtime_error(dnn_error("hbSysFlushMem(output)", code));
|
||||
}
|
||||
std::memcpy(output, output_mem.virAddr, sizeof(float) * kOutputFloats);
|
||||
std::memcpy(output, output_mem.virAddr, sizeof(float) * output_floats_);
|
||||
}
|
||||
|
||||
int input_floats() const { return input_floats_; }
|
||||
int output_floats() const { return output_floats_; }
|
||||
|
||||
private:
|
||||
static void validate_tensor(const hbDNNTensorProperties &props, int expected_count,
|
||||
int expected_type, const char *name) {
|
||||
const int count = element_count(props.validShape);
|
||||
if (count != expected_count) {
|
||||
std::ostringstream oss;
|
||||
oss << name << " valid element count " << count << " != " << expected_count;
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
static void validate_tensor(const hbDNNTensorProperties &props, int expected_type,
|
||||
const char *name) {
|
||||
if (props.tensorType != expected_type) {
|
||||
std::ostringstream oss;
|
||||
oss << name << " tensor type " << props.tensorType << " != " << expected_type;
|
||||
@@ -182,6 +178,8 @@ class BpuDnnPolicy {
|
||||
std::string model_name_;
|
||||
std::vector<hbDNNTensor> input_tensors_;
|
||||
std::vector<hbDNNTensor> output_tensors_;
|
||||
int input_floats_{0};
|
||||
int output_floats_{0};
|
||||
int bpu_core_{HB_BPU_CORE_ANY};
|
||||
int priority_{HB_DNN_PRIORITY_LOWEST};
|
||||
};
|
||||
@@ -201,14 +199,14 @@ void *rlgym_bpu_create(const char *model_path, int bpu_core, int priority,
|
||||
}
|
||||
}
|
||||
|
||||
int rlgym_bpu_infer(void *handle, const float *input450, float *output12, char *err,
|
||||
int rlgym_bpu_infer(void *handle, const float *input, float *output, char *err,
|
||||
int err_len) {
|
||||
try {
|
||||
set_error(err, err_len, "");
|
||||
if (handle == nullptr) {
|
||||
throw std::runtime_error("null policy handle");
|
||||
}
|
||||
static_cast<BpuDnnPolicy *>(handle)->infer(input450, output12);
|
||||
static_cast<BpuDnnPolicy *>(handle)->infer(input, output);
|
||||
return 0;
|
||||
} catch (const std::exception &e) {
|
||||
set_error(err, err_len, e.what());
|
||||
@@ -216,6 +214,20 @@ int rlgym_bpu_infer(void *handle, const float *input450, float *output12, char *
|
||||
}
|
||||
}
|
||||
|
||||
int rlgym_bpu_input_floats(void *handle) {
|
||||
if (handle == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<BpuDnnPolicy *>(handle)->input_floats();
|
||||
}
|
||||
|
||||
int rlgym_bpu_output_floats(void *handle) {
|
||||
if (handle == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<BpuDnnPolicy *>(handle)->output_floats();
|
||||
}
|
||||
|
||||
void rlgym_bpu_destroy(void *handle) {
|
||||
delete static_cast<BpuDnnPolicy *>(handle);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compatibility wrapper for the Gym 5-frame BPU deployment entrypoint."""
|
||||
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
entry = Path(__file__).resolve().parents[1] / "deploy_go1_rlgym_bpu_x5_fastcpp.py"
|
||||
runpy.run_path(str(entry), run_name="__main__")
|
||||
@@ -2,8 +2,8 @@
|
||||
"""Offline BPU policy smoke test for RDK X5.
|
||||
|
||||
This does not connect to the robot. It loads a BPU .bin and one raw float32
|
||||
input file, runs bpu_infer_lib repeatedly, and optionally checks the known
|
||||
00000.bin reference output captured from hrt_model_exec.
|
||||
input file, runs the C++ DNN API backend repeatedly, and optionally checks the
|
||||
known RobotLab 00000.bin reference output captured from hrt_model_exec.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -47,15 +47,19 @@ def main():
|
||||
|
||||
input_path = Path(args.input_bin).expanduser().resolve()
|
||||
data = np.fromfile(input_path, dtype=np.float32)
|
||||
if data.size != 450:
|
||||
raise ValueError(f"{input_path} has {data.size} float32 values, expected 450")
|
||||
|
||||
policy = BpuInferLibPolicy(args.bpu_model)
|
||||
if data.size != policy.input_size:
|
||||
raise ValueError(
|
||||
f"{input_path} has {data.size} float32 values, "
|
||||
f"but model expects {policy.input_size}"
|
||||
)
|
||||
action = policy(data)
|
||||
print("action", np.array2string(action, precision=6))
|
||||
print("action_max_abs", float(np.max(np.abs(action))))
|
||||
|
||||
if args.check_reference_00000:
|
||||
if policy.input_size != 450:
|
||||
raise ValueError("--check-reference-00000 is only valid for the 450-dim RobotLab reference input")
|
||||
diff = np.abs(action - REFERENCE_00000)
|
||||
print("reference_max_abs_diff", float(diff.max()))
|
||||
print("reference_mean_abs_diff", float(diff.mean()))
|
||||
|
||||
Reference in New Issue
Block a user