1# Copyright (c) Meta Platforms, Inc. and affiliates. 2# All rights reserved. 3# 4# This source code is licensed under the BSD-style license found in the 5# LICENSE file in the root directory of this source tree. 6 7# Example script for exporting simple models to flatbuffer 8 9# pyre-unsafe 10 11import argparse 12 13from typing import List 14 15import torch 16from executorch.devtools import BundledProgram 17from executorch.devtools.bundled_program.config import ( 18 MethodInputType, 19 MethodTestCase, 20 MethodTestSuite, 21) 22from executorch.devtools.bundled_program.serialize import ( 23 serialize_from_bundled_program_to_flatbuffer, 24) 25 26from executorch.exir import ExecutorchProgramManager 27from executorch.extension.export_util.utils import export_to_exec_prog 28 29from ...models import MODEL_NAME_TO_MODEL 30from ...models.model_factory import EagerModelFactory 31 32 33def save_bundled_program( 34 executorch_program: ExecutorchProgramManager, 35 method_test_suites: List[MethodTestSuite], 36 output_path: str, 37): 38 """ 39 Generates a bundled program from the given ET program and saves it to the specified path. 40 41 Args: 42 executorch_program: The ExecuTorch program to bundle. 43 method_test_suites: The MethodTestSuites which contains test cases to include in the bundled program. 44 output_path: Path to save the bundled program. 45 """ 46 47 bundled_program = BundledProgram(executorch_program, method_test_suites) 48 bundled_program_buffer = serialize_from_bundled_program_to_flatbuffer( 49 bundled_program 50 ) 51 52 with open(output_path, "wb") as file: 53 file.write(bundled_program_buffer) 54 55 56def export_to_bundled_program( 57 model_name: str, 58 output_directory: str, 59 model: torch.nn.Module, 60 example_inputs: MethodInputType, 61) -> None: 62 """ 63 Exports the given eager model to bundled program. 64 65 Args: 66 model_name: Name of the bundled program to export. 67 output_directory: Directory where the bundled program should be saved. 68 model: The eager model to export. 69 example_inputs: An example input for model's all method for single execution. 70 To simplify, here we assume that all inference methods have the same inputs. 71 """ 72 73 print("Exporting ET program...") 74 75 # pyre-ignore[6] 76 executorch_program = export_to_exec_prog(model, example_inputs) 77 78 print("Creating bundled test cases...") 79 method_names = [ 80 method.name for method in executorch_program.executorch_program.execution_plan 81 ] 82 83 # A model could have multiple entry point methods and each of them can have multiple inputs bundled for testing. 84 # This example demonstrates a model which has multiple entry point methods, whose name listed in method_names, to which we want 85 # to bundle two input test cases (example_inputs is used two times) for each inference method. 86 program_inputs = { 87 m_name: [example_inputs, example_inputs] for m_name in method_names 88 } 89 90 method_test_suites: List[MethodTestSuite] = [] 91 for m_name in method_names: 92 method_inputs = program_inputs[m_name] 93 94 # To create a bundled program, we first create every test cases from input. We leverage eager model 95 # to generate expected output for each test input, and use MethodTestCase to hold the information of 96 # each test case. We gather all MethodTestCase for same method into one MethodTestSuite, and generate 97 # bundled program by all MethodTestSuites. 98 method_test_cases: List[MethodTestCase] = [] 99 for method_input in method_inputs: 100 method_test_cases.append( 101 MethodTestCase( 102 inputs=method_input, 103 expected_outputs=model(*method_input), 104 ) 105 ) 106 107 method_test_suites.append( 108 MethodTestSuite( 109 method_name=m_name, 110 test_cases=method_test_cases, 111 ) 112 ) 113 114 save_bundled_program( 115 executorch_program, method_test_suites, f"{model_name}_bundled.bpte" 116 ) 117 118 119def main() -> None: 120 parser = argparse.ArgumentParser() 121 parser.add_argument( 122 "-m", 123 "--model_name", 124 required=True, 125 help=f"provide a model name. Valid ones: {list(MODEL_NAME_TO_MODEL.keys())}", 126 ) 127 parser.add_argument( 128 "-d", 129 "--dir", 130 default=".", 131 help="the directory to store the exported bundled program. Default is current directory.", 132 ) 133 134 args = parser.parse_args() 135 136 if args.model_name not in MODEL_NAME_TO_MODEL: 137 raise RuntimeError( 138 f"Model {args.model_name} is not a valid name. " 139 f"Available models are {list(MODEL_NAME_TO_MODEL.keys())}." 140 ) 141 142 model, example_inputs, _, _ = EagerModelFactory.create_model( 143 *MODEL_NAME_TO_MODEL[args.model_name] 144 ) 145 146 export_to_bundled_program(args.model_name, args.dir, model, example_inputs) 147 148 149if __name__ == "__main__": 150 main() # pragma: no cover 151