pytorch/torch/export
Shangdi Yu cf3247b74a Standalone compile API in _Exporter (#158139)
Given an `package: _ExportPackage`, users can get a ready-to-use workspace in `tmp_dir` by calling:
```python
package._compiled_and_package(
                tmp_dir + "/pt2_pacakge_name.pt2", True, package_example_inputs = True
            )
```

`tmp_dir` will contains:
- `main.cpp` (an example cpp file that create the models, if package_example_inputs is True, it'll also load the example inputs and run the models)
- `CMakeLists.txt`
- `pt2_pacakge_name/` (this is where the models are)
- `pt2_pacakge_name.pt2`
- `inputs.pt` files if package_example_inputs is True

Remaining TODOs
- support loading contants/weights
- the `package_example_inputs = True` option only supports a list of Tensors for now
- eventually we should remove the `torch` dependency, and use `SlimTensor`/`StableIValue` instead.

Test Plan:
```
python test/inductor/test_aot_inductor_package.py  -k test_compile_with_exporter
```

Example generated `main.cpp`:

```cpp
#include <dlfcn.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <torch/torch.h>
#include <vector>
#include <torch/csrc/inductor/aoti_torch/tensor_converter.h>
#include "package/data/aotinductor/Plus__default/Plus__default.h"
#include "package/data/aotinductor/Minus__default/Minus__default.h"

using torch::aot_inductor::AOTInductorModelPlus__default;
using torch::aot_inductor::AOTInductorModelMinus__default;
using torch::aot_inductor::ConstantHandle;
using torch::aot_inductor::ConstantMap;

int main(int argc, char* argv[]) {
    std::string device_str = "cpu";
    try {
        c10::Device device(device_str);
        // Load input tensors for model Plus__default
        std::vector<at::Tensor> input_tensors1;
        for (int j = 0; j < 2; ++j) {
            std::string filename = "Plus__default_input_" + std::to_string(j) + ".pt";
            std::ifstream in(filename, std::ios::binary);
            if (!in.is_open()) {
                std::cerr << "Failed to open file: " << filename << std::endl;
                return 1;
            }
            std::vector<char> buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
            torch::IValue ivalue = torch::pickle_load(buffer);
            input_tensors1.push_back(ivalue.toTensor().to(device));
        }

        // Load input tensors for model Minus__default
        std::vector<at::Tensor> input_tensors2;
        for (int j = 0; j < 2; ++j) {
            std::string filename = "Minus__default_input_" + std::to_string(j) + ".pt";
            std::ifstream in(filename, std::ios::binary);
            if (!in.is_open()) {
                std::cerr << "Failed to open file: " << filename << std::endl;
                return 1;
            }
            std::vector<char> buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
            torch::IValue ivalue = torch::pickle_load(buffer);
            input_tensors2.push_back(ivalue.toTensor().to(device));
        }

// Create array of input handles
        auto input_handles1 =
            torch::aot_inductor::unsafe_alloc_new_handles_from_tensors(input_tensors1);
        auto input_handles2 =
            torch::aot_inductor::unsafe_alloc_new_handles_from_tensors(input_tensors2);

// Create array for output handles
        AtenTensorHandle output_handle1;
        AtenTensorHandle output_handle2;

// Create and load models
        auto constants_map1 = std::make_shared<ConstantMap>();
        auto constants_array1 = std::make_shared<std::vector<ConstantHandle>>();
        auto model1 = AOTInductorModelPlus__default::Create(
            constants_map1, constants_array1, device_str,
            "package/data/aotinductor/Plus__default/");
        model1->load_constants();
        auto constants_map2 = std::make_shared<ConstantMap>();
        auto constants_array2 = std::make_shared<std::vector<ConstantHandle>>();
        auto model2 = AOTInductorModelMinus__default::Create(
            constants_map2, constants_array2, device_str,
            "package/data/aotinductor/Minus__default/");
        model2->load_constants();

// Run the models
        torch::aot_inductor::DeviceStreamType stream1 = nullptr;
        model1->run(&input_handles1[0], &output_handle1, stream1, nullptr);
        torch::aot_inductor::DeviceStreamType stream2 = nullptr;
        model2->run(&input_handles2[0], &output_handle2, stream2, nullptr);

// Convert output handles to tensors
        auto output_tensor1 =
            torch::aot_inductor::alloc_tensors_by_stealing_from_handles(&output_handle1, 1);
        auto output_tensor2 =
            torch::aot_inductor::alloc_tensors_by_stealing_from_handles(&output_handle2, 1);

// Validate outputs
        std::cout << "output_tensor1" << output_tensor1 << std::endl;
        std::cout << "output_tensor2" << output_tensor2 << std::endl;
        return 0;
    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
}

```

Rollback Plan:

Differential Revision: D78124705

Pull Request resolved: https://github.com/pytorch/pytorch/pull/158139
Approved by: https://github.com/desertfire
2025-07-15 18:47:56 +00:00
..
experimental Standalone compile API in _Exporter (#158139) 2025-07-15 18:47:56 +00:00
passes PEP585: More UP006 fixes (#146392) 2025-02-20 06:18:13 +00:00
pt2_archive [BE][1/16] fix typos in torch/ (#156311) 2025-07-09 11:02:22 +00:00
__init__.py [ez][export] Better error message for schema check in torch.export.load (#156361) 2025-06-19 04:50:56 +00:00
_draft_export.py [BE][PYFMT] migrate PYFMT for torch/[e-n]*/ to ruff format (#144553) 2025-06-17 08:18:47 +00:00
_remove_auto_functionalized_pass.py remove allow-untyped-defs from torch/export/_remove_auto_functionalized_pass.py (#144230) 2025-01-06 22:23:19 +00:00
_remove_effect_tokens_pass.py [BE][1/16] fix typos in torch/ (#156311) 2025-07-09 11:02:22 +00:00
_safeguard.py
_swap.py [BE][PYFMT] migrate PYFMT for torch/[e-n]*/ to ruff format (#144553) 2025-06-17 08:18:47 +00:00
_trace.py [BE][1/16] fix typos in torch/ (#156311) 2025-07-09 11:02:22 +00:00
_tree_utils.py PEP585 update - torch/export (#145165) 2025-01-19 20:56:55 +00:00
_unlift.py Fix from_node's graph_id in unlift() (#157943) 2025-07-10 03:23:55 +00:00
_wrapper_utils.py [reland] Make export._trace._WrapperModule work in strict mode (#146919) (#151264) 2025-04-15 18:35:34 +00:00
custom_obj.py
custom_ops.py Fix subclass access custom op bug (#149698) 2025-03-21 19:42:56 +00:00
decomp_utils.py Re-land exclude upsample_bilinear2d.vec and nearest2d.vec from default export decomposition table (#147153) 2025-02-19 23:03:29 +00:00
dynamic_shapes.py Remove is_jit_trace option (#157387) 2025-07-03 09:20:27 +00:00
exported_program.py [exported_program] Remove _postprocess_graph_module_outputs (#158059) 2025-07-11 02:40:15 +00:00
graph_signature.py [BE][1/16] fix typos in torch/ (#156311) 2025-07-09 11:02:22 +00:00
unflatten.py [BE][1/16] fix typos in torch/ (#156311) 2025-07-09 11:02:22 +00:00