Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 91 additions & 41 deletions examples/models/llama/export_llama_lib.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -676,47 +676,62 @@ def _validate_args(args):
)


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()

builder_exported.run_canonical_optimizations()

if args.export_only:
exit()

builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

modelname = builder_exported_to_edge.modelname

# to_backend
def _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
) -> LLMEdgeManager: # noqa: C901
partitioners = []

# Order matters here, dynamic quantization should be applied first when both xnnpack and xnnpack_extended_ops are enabled
if (
pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None
) or (args.xnnpack):
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=True)
)
partitioners.append(get_xnnpack_partitioner(dynamic_quant_only_partitioner=True))

# force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True
modelname = f"xnnpack_dq_{modelname}"
modelname = f"xnnpack_dq_{modelname}"

if args.xnnpack_extended_ops:
assert args.xnnpack, "xnnpack_extended_ops requires xnnpack to be enabled"
partitioners.append(
get_xnnpack_partitioner(dynamic_quant_only_partitioner=False)
)
modelname = f"xnnpack_{modelname}"

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

# TODO: Enable generating ETRecord with XNNPack and to_edge_transform_and_lower().
if args.generate_etrecord:
raise NotImplementedError(
"export_llama does not support XNNPack and generating ETRecord at the moment."
)

builder = builder_exported.pt2e_quantize(quantizers).to_edge_transform_and_lower(
partitioners
)
if args.verbose:
print_delegation_info(builder.edge_manager.exported_program().graph_module)

return builder.to_executorch(passes=additional_passes)


def _to_edge_and_lower_llama( # noqa: C901
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
):
builder_exported_to_edge = builder_exported.pt2e_quantize(
quantizers
).export_to_edge()

# to_backend
partitioners = []
if args.vulkan:
partitioners.append(
get_vulkan_partitioner(
Expand All@@ -731,7 +746,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
modelname = f"vulkan_{modelname}"

# Need to remove asserts from the graph to prevent graph breaks
# pyre-ignore: Undefined attribute [16]: `Optional` has no attribute `exported_program`.
remove_asserts(builder_exported_to_edge.edge_manager.exported_program())

if args.mps:
Expand DownExpand Up@@ -760,13 +774,11 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
# pyre-ignore: Undefined import [21]: Could not find a module corresponding to import `executorch.backends.qualcomm.utils.utils`
from executorch.backends.qualcomm.utils.utils import _transform, tag_quant_io

# pyre-ignore: Undefined attribute [16]: Module `executorch.backends` has no attribute `qualcomm`, Optional type has no attribute `exported_program`
_transform(builder_exported_to_edge.edge_manager.exported_program())

if args.num_sharding > 0:
model_sharding.split_graph(
builder_exported_to_edge.edge_manager.exported_program(),
# pyre-fixme[16]: `Optional` has no attribute `__getitem__`.
builder_exported_to_edge.metadata["get_n_layers"],
shares=args.num_sharding,
)
Expand All@@ -792,19 +804,15 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
atten.head_dim,
)
)
# pyre-ignore
tag_quant_io(
builder_exported_to_edge.edge_manager.exported_program().graph_module,
partial(get_custom_quant_ios_dtype, cache_shape), # pyre-ignore
partial(get_custom_quant_ios_dtype, cache_shape),
)

logging.info("Lowering model using following partitioner(s): ")
for partitioner in partitioners:
logging.info(f"--> {partitioner.__class__.__name__}")

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]
if args.generate_etrecord:
if not builder_exported_to_edge.edge_manager:
raise ValueError("Unable to generate etrecord due to missing edge manager.")
Expand All@@ -818,7 +826,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(
Expand All@@ -840,11 +847,55 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
if args.num_sharding > 0 and args.qnn:
from executorch.backends.qualcomm.utils.utils import canonicalize_program

# pyre-fixme[16]: Module `backends` has no attribute `qualcomm`.
canonicalize_program(builder.edge_manager.exported_program())

builder = builder.to_executorch(passes=additional_passes)

return builder


def _export_llama(args) -> LLMEdgeManager: # noqa: C901
_validate_args(args)

pt2e_quant_params, quantizers, quant_dtype = get_quantizer_and_quant_params(args)

additional_passes = []
if args.model in TORCHTUNE_DEFINED_MODELS:
additional_passes = [InitializedMutableBufferPass(["kv_cache_pos"])]

# export_to_edge
builder_exported = _prepare_for_llama_export(args).export()
builder_exported.run_canonical_optimizations()
modelname = builder_exported.modelname

if args.export_only:
exit()

if pt2e_quant_params is not None and pt2e_quant_params.quantize_linear is not None:
# Force xnnpack to be true if pt2e_quant_params is not None and args.xnnpack is False
args.xnnpack = True

if args.xnnpack:
builder = _to_edge_and_lower_llama_xnnpack(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)
else:
builder = _to_edge_and_lower_llama(
builder_exported,
modelname,
additional_passes,
pt2e_quant_params,
quantizers,
quant_dtype,
args,
)

if args.profile_memory:
generate_memory_trace(builder.export_program, "memory_profile.json")

Expand All@@ -866,7 +917,6 @@ def _export_llama(args) -> LLMEdgeManager: # noqa: C901
output_file = f"{builder.output_dir}/{modelname}.pte"

builder.save_to_pte(output_file)

return builder


Expand Down
1 change: 0 additions & 1 deletion examples/models/llava/export_llava.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,7 +67,6 @@ def export(self) -> "LlavaEdgeManager":
dynamic_shapes=dynamic_shape,
strict=False,
)
# pyre-ignore: Incompatible attribute type [8]: Attribute `pre_autograd_graph_module` declared in class `LLMEdgeManager` has type `Optional[GraphModule]` but is used as type `Module`.
self.pre_autograd_graph_module = self.export_program.module()
return self

Expand Down
29 changes: 23 additions & 6 deletions extension/llm/export/builder.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@
DuplicateDynamicQuantChainPass,
)
from executorch.backends.xnnpack._passes.convert_to_linear import ConvertToLinearPass
from executorch.exir import EdgeProgramManager
from executorch.exir import EdgeProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.partitioner import Partitioner

from executorch.exir.backend.utils import format_delegated_graph
Expand All@@ -39,7 +39,7 @@
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer import Quantizer
from torch.ao.quantization.quantizer.composable_quantizer import ComposableQuantizer
from torch.export import export_for_training
from torch.export import export_for_training, ExportedProgram
from torch.nn.attention import SDPBackend

FORMAT = "[%(levelname)s %(asctime)s %(filename)s:%(lineno)s] %(message)s"
Expand DownExpand Up@@ -89,8 +89,8 @@ def __init__(
dynamic_shapes: Optional[Any] = None,
):
self.model = model
# graph module returned from export()
self.pre_autograd_graph_module: Optional[torch.fx.GraphModule] = None
self.pre_autograd_exported_program: Optional[ExportedProgram] = None
self.pre_autograd_graph_module: Optional[torch.nn.Module] = None
self.modelname = modelname
self.max_seq_len = max_seq_len
self.dtype = dtype
Expand DownExpand Up@@ -218,8 +218,8 @@ def export(self) -> "LLMEdgeManager":
kwargs=self.example_kwarg_inputs,
dynamic_shapes=dynamic_shape,
)
# pyre-fixme[8]: Attribute has type `Optional[GraphModule]`; used as
# `Module`.
self.pre_autograd_exported_program = exported_module
self.pre_autograd_graph_module = exported_module.module()
if hasattr(self.args, "export_only") and self.args.export_only:
torch.export.save(exported_module, self.args.output_name)
Expand DownExpand Up@@ -330,7 +330,10 @@ def pt2e_quantize(self, quantizers: Optional[List[Quantizer]]) -> "LLMEdgeManage
assert (
self.pre_autograd_graph_module is not None
), "Please run export() first"
m = prepare_pt2e(self.pre_autograd_graph_module, composed_quantizer)
m = prepare_pt2e(
self.pre_autograd_graph_module, # pyre-ignore[6]
composed_quantizer,
)
logging.info(
f"Calibrating with tasks: {self.calibration_tasks}, limit: {self.calibration_limit}, calibration_data: {self.calibration_data}, tokenizer_path: {self.tokenizer_path}, seq_length: {self.calibration_seq_length}"
)
Expand DownExpand Up@@ -430,6 +433,20 @@ def to_backend(self, partitioners: Optional[List[Partitioner]]) -> "LLMEdgeManag

return self

def to_edge_transform_and_lower(
self, partitioners: Optional[List[Partitioner]]
) -> "LLMEdgeManager":
if partitioners is None:
logging.info("No partitioner provided, skipping backend lowering...")
edge_config = self._get_edge_config()
self.edge_manager = to_edge_transform_and_lower(
self.pre_autograd_exported_program,
partitioner=partitioners,
compile_config=edge_config,
constant_methods=self.metadata,
)
return self

def to_executorch(
self, passes: Optional[List[ExportPass]] = None
) -> "LLMEdgeManager":
Expand Down