/** * NeuroFlow Python Bindings * * 使用pybind11绑定C++核心到Python * 保持与原Python API兼容 */ #include #include #include #include #include "neuroflow/model.hpp" #include "neuroflow/tensor.hpp" #include "neuroflow/networks.hpp" #include "neuroflow/memory.hpp" #include "neuroflow/multimodal_model.hpp" namespace py = pybind11; using namespace neuroflow; // numpy数组转换为Tensor Tensor numpy_to_tensor(py::array_t arr) { py::buffer_info buf = arr.request(); std::vector shape; for (auto dim : buf.shape) shape.push_back(static_cast(dim)); Tensor t(shape, QuantType::FP32); float* data = t.as_fp32(); // 新创建的Tensor,可以用非const指针 float* src = static_cast(buf.ptr); memcpy(data, src, t.data_size); return t; } // Tensor转换为numpy数组 py::array_t tensor_to_numpy(const Tensor& t) { if (t.dtype != QuantType::FP32) { throw std::runtime_error("Only FP32 tensors can be converted to numpy"); } std::vector shape; for (auto dim : t.shape) shape.push_back(static_cast(dim)); const float* data = t.as_fp32(); // 创建numpy数组并拷贝数据 py::array_t arr(shape); py::buffer_info buf = arr.request(); memcpy(buf.ptr, data, t.data_size); return arr; } PYBIND11_MODULE(_core, m) { m.doc() = "NeuroFlow C++ Core - Lightweight Brain-Inspired Neural Network"; // 版本 m.attr("__version__") = "1.0.0"; // QuantType枚举 py::enum_(m, "QuantType") .value("FP32", QuantType::FP32) .value("FP16", QuantType::FP16) .value("INT8", QuantType::INT8) .value("INT4", QuantType::INT4) .value("FP8_E4M3", QuantType::FP8_E4M3) .value("FP8_E5M2", QuantType::FP8_E5M2) .export_values(); // MemoryLayout枚举 py::enum_(m, "MemoryLayout") .value("ROW_MAJOR", MemoryLayout::ROW_MAJOR) .value("COL_MAJOR", MemoryLayout::COL_MAJOR) .export_values(); // Tensor类 py::class_(m, "Tensor") .def(py::init<>()) .def(py::init, QuantType>(), py::arg("shape"), py::arg("dtype") = QuantType::FP32) .def_property_readonly("shape", [](const Tensor& t) { return t.shape; }) .def_property_readonly("dtype", [](const Tensor& t) { return t.dtype; }) .def_property_readonly("numel", &Tensor::numel) .def_property_readonly("data_size", [](const Tensor& t) { return t.data_size; }) .def("clone", &Tensor::clone) .def("reshape", &Tensor::reshape) .def("as_numpy", &tensor_to_numpy) .def("from_numpy", [](Tensor& t, py::array_t arr) { py::buffer_info buf = arr.request(); float* data = t.as_fp32(); memcpy(data, buf.ptr, t.data_size); }) .def_static("from_numpy_array", &numpy_to_tensor); // TensorOps py::class_(m, "TensorOps") .def_static("gemm", &TensorOps::gemm, py::arg("A"), py::arg("B"), py::arg("C"), py::arg("transA") = false, py::arg("transB") = false, py::arg("alpha") = 1.0f, py::arg("beta") = 0.0f) .def_static("layer_norm", &TensorOps::layer_norm, py::arg("x"), py::arg("weight"), py::arg("bias"), py::arg("eps") = 1e-5f) .def_static("gelu", &TensorOps::gelu) .def_static("softmax", &TensorOps::softmax, py::arg("x"), py::arg("axis") = -1) .def_static("dropout", &TensorOps::dropout, py::arg("x"), py::arg("rate"), py::arg("training") = true) .def_static("add", &TensorOps::add) .def_static("mul", &TensorOps::mul) .def_static("concat", &TensorOps::concat, py::arg("tensors"), py::arg("axis") = 0) .def_static("quantize_int8", &TensorOps::quantize_int8) .def_static("dequantize_int8", &TensorOps::dequantize_int8); // Linear层 py::class_(m, "Linear") .def(py::init(), py::arg("in_features"), py::arg("out_features"), py::arg("use_bias") = true, py::arg("quant") = false) .def("forward", &Linear::forward) .def("quantize", &Linear::quantize) .def_property_readonly("weight", [](Linear& l) { return l.weight; }) .def_property_readonly("bias", [](Linear& l) { return l.bias; }) .def_property_readonly("quantized", [](Linear& l) { return l.quantized; }); // LayerNorm py::class_(m, "LayerNorm") .def(py::init(), py::arg("dim"), py::arg("eps") = 1e-5f) .def("forward", &LayerNorm::forward) .def_property_readonly("weight", [](LayerNorm& l) { return l.weight; }) .def_property_readonly("bias", [](LayerNorm& l) { return l.bias; }); // ExecutiveControlNetwork py::class_(m, "ECNOutput") .def_property_readonly("decision", [](ExecutiveControlNetwork::Output& o) { return o.decision; }) .def_property_readonly("value", [](ExecutiveControlNetwork::Output& o) { return o.value; }) .def_property_readonly("hidden_states", [](ExecutiveControlNetwork::Output& o) { return o.hidden_states; }); py::class_(m, "ExecutiveControlNetwork") .def(py::init(), py::arg("input_dim"), py::arg("hidden_dim"), py::arg("output_dim"), py::arg("num_layers") = 2) .def("forward", &ExecutiveControlNetwork::forward) .def("set_training", &ExecutiveControlNetwork::set_training) .def("quantize", &ExecutiveControlNetwork::quantize); // DefaultModeNetwork py::class_(m, "DMNOutput") .def_property_readonly("vision", [](DefaultModeNetwork::Output& o) { return o.vision; }) .def_property_readonly("associations", [](DefaultModeNetwork::Output& o) { return o.associations; }) .def_property_readonly("latent", [](DefaultModeNetwork::Output& o) { return o.latent; }); py::class_(m, "DefaultModeNetwork") .def(py::init(), py::arg("memory_dim"), py::arg("latent_dim"), py::arg("num_associations") = 8) .def("forward", &DefaultModeNetwork::forward) .def("quantize", &DefaultModeNetwork::quantize); // SalienceNetwork py::class_(m, "SNOutput") .def_property_readonly("saliency", [](SalienceNetwork::Output& o) { return o.saliency; }) .def_property_readonly("gates", [](SalienceNetwork::Output& o) { return o.gates; }) .def_property_readonly("anomaly", [](SalienceNetwork::Output& o) { return o.anomaly; }); py::class_(m, "SalienceNetwork") .def(py::init(), py::arg("input_dim"), py::arg("hidden_dim")) .def("forward", [](SalienceNetwork& sn, const Tensor& x) { return sn.forward(x); }, py::arg("x")) .def("forward_with_baseline", [](SalienceNetwork& sn, const Tensor& x, const Tensor& baseline) { return sn.forward(x, &baseline); }, py::arg("x"), py::arg("baseline")) .def("quantize", &SalienceNetwork::quantize); // MemoryConsolidationModule py::class_(m, "MemoryResult") .def_property_readonly("retrieved", [](MemoryConsolidationModule::RetrievalResult& r) { return r.retrieved; }) .def_property_readonly("attention", [](MemoryConsolidationModule::RetrievalResult& r) { return r.attention; }); py::class_(m, "MemoryConsolidationModule") .def(py::init(), py::arg("input_dim"), py::arg("memory_slots") = 64, py::arg("memory_dim") = 128, py::arg("ltp_rate") = 0.01f) .def("encode", &MemoryConsolidationModule::encode) .def("retrieve", &MemoryConsolidationModule::retrieve) .def("consolidate", &MemoryConsolidationModule::consolidate) .def("forward", &MemoryConsolidationModule::forward); // LatentKVCache (MLA) py::class_(m, "LatentKVCache") .def(py::init(), py::arg("model_dim"), py::arg("heads"), py::arg("latent_dim"), py::arg("max_len") = 4096) .def("forward", &LatentKVCache::forward, py::arg("x"), py::arg("use_cache") = true) .def("clear_cache", &LatentKVCache::clear_cache) .def("cache_size_bytes", &LatentKVCache::cache_size_bytes) .def("memory_saving_ratio", &LatentKVCache::memory_saving_ratio); // NeuroFlowModel::Config py::class_(m, "ModelConfig") .def(py::init<>()) .def_readwrite("input_dim", &NeuroFlowModel::Config::input_dim) .def_readwrite("hidden_dim", &NeuroFlowModel::Config::hidden_dim) .def_readwrite("output_dim", &NeuroFlowModel::Config::output_dim) .def_readwrite("memory_dim", &NeuroFlowModel::Config::memory_dim) .def_readwrite("memory_slots", &NeuroFlowModel::Config::memory_slots) .def_readwrite("num_layers", &NeuroFlowModel::Config::num_layers) .def_readwrite("num_associations", &NeuroFlowModel::Config::num_associations) .def_readwrite("use_quantization", &NeuroFlowModel::Config::use_quantization) .def_readwrite("use_mla", &NeuroFlowModel::Config::use_mla) .def_readwrite("mla_latent_dim", &NeuroFlowModel::Config::mla_latent_dim); // NeuroFlowModel::Output py::class_(m, "ModelOutput") .def_property_readonly("output", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.output); }) .def_property_readonly("decision", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.decision); }) .def_property_readonly("value", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.value); }) .def_property_readonly("saliency", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.saliency); }) .def_property_readonly("ecn_gate", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.ecn_gate); }) .def_property_readonly("dmn_gate", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.dmn_gate); }) .def_property_readonly("anomaly", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.anomaly); }) .def_property_readonly("mem_attention", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.mem_attention); }) .def_property_readonly("retrieved_mem", [](NeuroFlowModel::Output& o) { return tensor_to_numpy(o.retrieved_mem); }) .def_property_readonly("manifold", [](NeuroFlowModel::Output& o) { if (o.manifold.data) return tensor_to_numpy(o.manifold); return py::array_t(); }); // NeuroFlowModel::Stats py::class_(m, "ModelStats") .def_readonly("total_params", &NeuroFlowModel::Stats::total_params) .def_readonly("memory_bytes", &NeuroFlowModel::Stats::memory_bytes) .def_readonly("quantization_ratio", &NeuroFlowModel::Stats::quantization_ratio); // NeuroFlowModel主类 py::class_(m, "NeuroFlowModel") .def(py::init<>()) .def(py::init(), py::arg("config")) .def("forward", [](NeuroFlowModel& m, py::array_t x, py::object memory_input, bool consolidate, bool return_manifold) { Tensor input = numpy_to_tensor(x); const Tensor* mem_ptr = nullptr; Tensor mem; if (!memory_input.is_none()) { mem = numpy_to_tensor(memory_input.cast>()); mem_ptr = &mem; } return m.forward(input, mem_ptr, consolidate, return_manifold); }, py::arg("x"), py::arg("memory_input") = py::none(), py::arg("consolidate") = false, py::arg("return_manifold") = false) .def("get_manifold_trajectory", [](NeuroFlowModel& m, py::array_t x, size_t steps) { Tensor input = numpy_to_tensor(x); auto trajectory = m.get_manifold_trajectory(input, steps); py::list result; for (auto& t : trajectory) { result.append(tensor_to_numpy(t)); } return result; }, py::arg("x"), py::arg("steps") = 10) .def("set_training", &NeuroFlowModel::set_training) .def("quantize", &NeuroFlowModel::quantize) .def("get_stats", &NeuroFlowModel::get_stats) .def("save", &NeuroFlowModel::save) .def("load", &NeuroFlowModel::load) .def("forward_text", [](NeuroFlowModel& m, py::array_t x) { Tensor input = numpy_to_tensor(x); return m.forward(input); }) .def_property_readonly("config", [](NeuroFlowModel& m) { return m.config; }); // NeuroFlowLite py::class_(m, "NeuroFlowLite") .def(py::init(), py::arg("input_dim") = 512); // 便捷函数 m.def("create_tensor", [](py::array_t arr) { return numpy_to_tensor(arr); }, "Create Tensor from numpy array"); m.def("benchmark", []() { NeuroFlowModel::Config cfg; cfg.input_dim = 512; cfg.hidden_dim = 256; cfg.output_dim = 10; NeuroFlowModel original(cfg); NeuroFlowModel::Config lite_cfg; lite_cfg.input_dim = 512; lite_cfg.hidden_dim = 128; lite_cfg.output_dim = 10; lite_cfg.memory_dim = 64; lite_cfg.memory_slots = 32; lite_cfg.num_layers = 1; lite_cfg.use_quantization = true; NeuroFlowModel lite(lite_cfg); auto orig_stats = original.get_stats(); auto lite_stats = lite.get_stats(); py::dict result; result["original_params"] = orig_stats.total_params; result["original_memory_mb"] = orig_stats.memory_bytes / 1024.0 / 1024.0; result["lite_params"] = lite_stats.total_params; result["lite_memory_mb"] = lite_stats.memory_bytes / 1024.0 / 1024.0; result["size_reduction"] = 1.0 - static_cast(lite_stats.total_params) / orig_stats.total_params; return result; }, "Benchmark comparison between original and lite models"); // ================================================================ // MultiModal Bindings // ================================================================ // VisionEncoder py::class_(m, "VisionEncoder") .def(py::init(), py::arg("image_size") = 224, py::arg("patch_size") = 16, py::arg("embed_dim") = 256, py::arg("num_heads") = 8, py::arg("num_layers") = 4) .def("forward", &VisionEncoder::forward); // CrossModalFusion py::class_(m, "FusionOutput") .def_readonly("fused", &CrossModalFusion::Output::fused) .def_readonly("text_feat", &CrossModalFusion::Output::text_feat) .def_readonly("image_feat", &CrossModalFusion::Output::image_feat) .def_readonly("similarity", &CrossModalFusion::Output::similarity); py::class_(m, "CrossModalFusion") .def(py::init(), py::arg("text_dim") = 512, py::arg("vision_dim") = 256, py::arg("fusion_dim") = 256) .def("forward", &CrossModalFusion::forward); // NeuroFlowMultiModal::Config py::class_(m, "MultiModalConfig") .def(py::init<>()) .def_readwrite("text_dim", &NeuroFlowMultiModal::Config::text_dim) .def_readwrite("image_size", &NeuroFlowMultiModal::Config::image_size) .def_readwrite("patch_size", &NeuroFlowMultiModal::Config::patch_size) .def_readwrite("vision_dim", &NeuroFlowMultiModal::Config::vision_dim) .def_readwrite("fusion_dim", &NeuroFlowMultiModal::Config::fusion_dim) .def_readwrite("hidden_dim", &NeuroFlowMultiModal::Config::hidden_dim) .def_readwrite("output_dim", &NeuroFlowMultiModal::Config::output_dim) .def_readwrite("memory_dim", &NeuroFlowMultiModal::Config::memory_dim) .def_readwrite("memory_slots", &NeuroFlowMultiModal::Config::memory_slots) .def_readwrite("num_layers", &NeuroFlowMultiModal::Config::num_layers) .def_readwrite("num_associations", &NeuroFlowMultiModal::Config::num_associations) .def_readwrite("vision_layers", &NeuroFlowMultiModal::Config::vision_layers) .def_readwrite("vision_heads", &NeuroFlowMultiModal::Config::vision_heads) .def_readwrite("use_quantization", &NeuroFlowMultiModal::Config::use_quantization) .def_readwrite("use_mla", &NeuroFlowMultiModal::Config::use_mla) .def_readwrite("mla_latent_dim", &NeuroFlowMultiModal::Config::mla_latent_dim); // NeuroFlowMultiModal::Output py::class_(m, "MultiModalOutput") .def_property_readonly("output", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.output); }) .def_property_readonly("decision", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.decision); }) .def_property_readonly("value", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.value); }) .def_property_readonly("saliency", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.saliency); }) .def_property_readonly("text_image_sim", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.text_image_sim); }) .def_property_readonly("gates", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.gates); }) .def_property_readonly("anomaly", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.anomaly); }) .def_property_readonly("retrieved_mem", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.retrieved_mem); }) .def_property_readonly("vision_feat", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.vision_feat); }) .def_property_readonly("text_feat", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.text_feat); }) .def_property_readonly("fused_feat", [](NeuroFlowMultiModal::Output& o) { return tensor_to_numpy(o.fused_feat); }); // NeuroFlowMultiModal py::class_(m, "NeuroFlowMultiModal") .def(py::init(), py::arg("config")) .def("forward_multimodal", [](NeuroFlowMultiModal& mm, py::array_t text, py::array_t image, bool consolidate, bool return_manifold) { return mm.forward_multimodal(numpy_to_tensor(text), numpy_to_tensor(image), consolidate, return_manifold); }, py::arg("text"), py::arg("image"), py::arg("consolidate") = false, py::arg("return_manifold") = false) .def("forward_text", [](NeuroFlowMultiModal& mm, py::array_t text) { return mm.forward_text(numpy_to_tensor(text)); }, py::arg("text")) .def("forward_image", [](NeuroFlowMultiModal& mm, py::array_t image) { return mm.forward_image_only(numpy_to_tensor(image)); }, py::arg("image")) .def("set_training", &NeuroFlowMultiModal::set_training) .def("quantize", &NeuroFlowMultiModal::quantize) .def("get_stats", &NeuroFlowMultiModal::get_stats) .def("save", &NeuroFlowMultiModal::save) .def("load", &NeuroFlowMultiModal::load) .def_readonly("config", &NeuroFlowMultiModal::config); // 便捷:创建默认多模态模型 m.def("create_multimodal", [](size_t text_dim, size_t image_size, size_t output_dim, bool quantize) { NeuroFlowMultiModal::Config cfg; cfg.text_dim = text_dim; cfg.image_size = image_size; cfg.output_dim = output_dim; cfg.use_quantization = quantize; return std::make_unique(cfg); }, py::arg("text_dim") = 512, py::arg("image_size") = 224, py::arg("output_dim") = 10, py::arg("quantize") = false); }