This is an automated email from the ASF dual-hosted git repository.
syfeng pushed a commit to branch unity
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/unity by this push:
new e0518da2a5 [Unity][MSC][M2.3] Add tracker for track layer datas
(#16207)
e0518da2a5 is described below
commit e0518da2a597a61f5c5a6613b2a54b2e46a8039f
Author: Archermmt <[email protected]>
AuthorDate: Sun Dec 10 13:34:08 2023 +0800
[Unity][MSC][M2.3] Add tracker for track layer datas (#16207)
* add tracker
* remove distiller
* format fix
---
python/tvm/contrib/msc/core/ir/graph.py | 76 ++++++
python/tvm/contrib/msc/core/runtime/runner.py | 286 +++++++++++++++------
python/tvm/contrib/msc/core/tools/__init__.py | 1 +
python/tvm/contrib/msc/core/tools/prune/method.py | 6 +-
python/tvm/contrib/msc/core/tools/prune/pruner.py | 149 +++++++----
python/tvm/contrib/msc/core/tools/tool.py | 256 +++++++++---------
.../tools => core/tools/track}/__init__.py | 5 +-
python/tvm/contrib/msc/core/tools/track/method.py | 102 ++++++++
python/tvm/contrib/msc/core/tools/track/tracker.py | 185 +++++++++++++
python/tvm/contrib/msc/core/utils/info.py | 37 ++-
python/tvm/contrib/msc/core/utils/log.py | 21 +-
python/tvm/contrib/msc/core/utils/message.py | 23 ++
.../msc/framework/tensorflow/runtime/runner.py | 2 +-
.../msc/framework/tensorflow/tools/__init__.py | 1 +
.../tensorflow/tools/{ => track}/__init__.py | 4 +-
.../framework/tensorflow/tools/track/tracker.py | 55 ++++
.../msc/framework/tensorrt/tools/__init__.py | 1 +
.../tools => tensorrt/tools/track}/__init__.py | 4 +-
.../msc/framework/tensorrt/tools/track/tracker.py | 159 ++++++++++++
.../msc/framework/torch/frontend/translate.py | 2 +-
.../contrib/msc/framework/torch/tools/__init__.py | 1 +
.../tools => torch/tools/track}/__init__.py | 4 +-
.../msc/framework/torch/tools/track/tracker.py | 55 ++++
.../contrib/msc/framework/tvm/tools/__init__.py | 1 +
.../tools => tvm/tools/track}/__init__.py | 4 +-
.../msc/framework/tvm/tools/track/tracker.py | 155 +++++++++++
python/tvm/contrib/msc/pipeline/manager.py | 112 +++++---
src/contrib/msc/core/ir/graph.cc | 17 ++
src/contrib/msc/core/ir/graph.h | 2 +-
src/contrib/msc/framework/tensorrt/codegen.cc | 37 ++-
src/contrib/msc/framework/tensorrt/codegen.h | 4 +
tests/python/contrib/test_msc/test_tools.py | 102 +++++---
32 files changed, 1491 insertions(+), 378 deletions(-)
diff --git a/python/tvm/contrib/msc/core/ir/graph.py
b/python/tvm/contrib/msc/core/ir/graph.py
index 8fabed30ac..51727cd089 100644
--- a/python/tvm/contrib/msc/core/ir/graph.py
+++ b/python/tvm/contrib/msc/core/ir/graph.py
@@ -104,6 +104,17 @@ class MSCTensor(Object):
return False
return True
+ def to_json(self) -> str:
+ """Dump the tensor to json.
+
+ Returns
+ -------
+ tensor_json: string
+ The tensor in json format.
+ """
+
+ return _ffi_api.MSCTensorToJson(self)
+
def inspect(self) -> dict:
"""Extract important info of the tensor.
@@ -117,6 +128,45 @@ class MSCTensor(Object):
tensor_des["layout"] = self.layout.name if self.layout else ""
return tensor_des
+ @classmethod
+ def from_json(cls, json_str: str, **options) -> object:
+ """Load the tensor from json.
+
+ Parameters
+ ----------
+ json_str: string
+ The file_path or json string.
+ options: dict
+ The items to be changed.
+
+ Returns
+ -------
+ tensor: MSCTensor
+ The tensor.
+ """
+
+ dict_obj = msc_utils.load_dict(json_str)
+ dict_obj.update(options)
+ return _ffi_api.MSCTensorFromJson(msc_utils.dump_dict(dict_obj))
+
+ def clone(self, **options) -> object:
+ """Clone the tensor.
+
+ Parameters
+ ----------
+ json_str: string
+ The file_path or json string.
+ options: dict
+ The items to be changed.
+
+ Returns
+ -------
+ new_tensor: MSCTensor
+ The cloned tensor.
+ """
+
+ return MSCTensor.from_json(self.to_json(), **options)
+
@property
def dtype_name(self) -> str:
return _ffi_api.MSCTensorDTypeName(self)
@@ -391,6 +441,19 @@ class WeightJoint(BaseJoint):
friends,
)
+ def set_attr(self, key: str, value: str):
+ """Set attribute to node
+
+ Parameters
+ -------
+ key: str
+ The key of the attribute.
+ value: str
+ The value.
+ """
+
+ _ffi_api.WeightJointSetAttr(self, key, value)
+
def get_attrs(self) -> Dict[str, str]:
"""Get all the attributes from node
@@ -536,6 +599,19 @@ class MSCGraph(BaseGraph):
return _ffi_api.MSCGraphFindTensor(self, name)
+ def set_tensor_alias(self, tensor: MSCTensor, alias: str):
+ """Set alis for the tensor
+
+ Parameters
+ -------
+ tensor: MSCTensor
+ The tensor.
+ alias: str
+ The alias.
+ """
+
+ _ffi_api.MSCGraphSetTensorAlias(self, tensor, alias)
+
def find_producer(self, ref: Union[str, MSCTensor]) -> MSCJoint:
"""Find producer by tensor_name or tensor.
diff --git a/python/tvm/contrib/msc/core/runtime/runner.py
b/python/tvm/contrib/msc/core/runtime/runner.py
index 12e2dec02a..dcf24225fe 100644
--- a/python/tvm/contrib/msc/core/runtime/runner.py
+++ b/python/tvm/contrib/msc/core/runtime/runner.py
@@ -20,13 +20,13 @@
import os
import json
import logging
-from typing import Dict, Optional, Any, List, Tuple, Union
+from typing import Dict, Optional, Any, List, Tuple, Union, Iterable
import numpy as np
import tvm
from tvm.contrib.msc.core.ir import MSCGraph
from tvm.contrib.msc.core.frontend import from_relax
-from tvm.contrib.msc.core.tools import BaseTool, ToolType, create_tool
+from tvm.contrib.msc.core.tools import BaseTool, ToolType, create_tool,
remove_tools
from tvm.contrib.msc.core.utils.namespace import MSCFramework
from tvm.contrib.msc.core.utils.message import MSCStage
from tvm.contrib.msc.core import utils as msc_utils
@@ -76,9 +76,9 @@ class BaseRunner(object):
logger: logging.Logger = None,
):
self._mod = mod
- self._tools_config = tools_config or {}
- self._translate_config = translate_config or {}
- self._generate_config = generate_config or {}
+ self._tools_config = msc_utils.copy_dict(tools_config)
+ self._translate_config = msc_utils.copy_dict(translate_config)
+ self._generate_config = msc_utils.copy_dict(generate_config)
self._stage = stage
self._name = name
self._device = device if self._device_enabled(device) else "cpu"
@@ -102,16 +102,19 @@ class BaseRunner(object):
if "build_folder" not in self._generate_config:
self._generate_config["build_folder"] = msc_utils.get_build_dir()
- if self._tools_config:
- if "codegen" not in self._generate_config:
- self._generate_config["codegen"] = {}
- self._generate_config["codegen"].update({"use_tools": True,
"tools_tag": self._name})
self._graphs, self._weights = [], []
self._model, self._model_info = None, {}
self._runnable = None
+ # Setup tools
self._tools = {}
+ if self._tools_config:
+ self._update_codegen({"use_tools": True, "tools_tag": self._name})
+ for t_type, config in self._tools_config.items():
+ self._tools[t_type] = create_tool(
+ self.framework, t_type, self._name, stage=self._stage,
**config
+ )
return {
- "tools_config": self._tools_config,
+ "tools": {k: v.tool_style() for k, v in self._tools.items()},
"translate_config": self._translate_config,
"generate_config": self._generate_config,
"name": self._name,
@@ -121,21 +124,28 @@ class BaseRunner(object):
}
def change_stage(self, stage: str):
- """Change the stage of tools and strategy"""
+ """Change the stage of runner and tools"""
self._stage = stage
for tool in self._tools.values():
tool.change_stage(stage)
- def build(self, cache_dir: msc_utils.MSCDirectory = None, build_graph:
bool = False) -> Any:
+ def change_logger(self, logger: logging.Logger):
+ """Change the logger of runner and tools"""
+
+ self._logger = logger
+ for tool in self._tools.values():
+ tool.change_logger(logger)
+
+ def build(self, cache_dir: msc_utils.MSCDirectory = None, force_build:
bool = False) -> Any:
"""Build the runnable object
Parameters
-------
cache_dir: MSCDirectory
cache path for save/load info
- build_graph: bool
- Whether to build the MSCGraphs.
+ force_build: bool
+ Whether to force build the runner.
Returns
-------
@@ -143,89 +153,137 @@ class BaseRunner(object):
The runnable object.
"""
+ if force_build:
+ self._graphs, self._weights = [], []
+ self._model, self._model_info = None, {}
+ self._runnable = None
if cache_dir and os.path.isfile(cache_dir.relpath("cache_info.json")):
cache_info =
msc_utils.load_dict(cache_dir.relpath("cache_info.json"))
else:
cache_info = {}
- # Create tools
- if self._tools_config:
- for t_type, config in self._tools_config.items():
- self._tools[t_type] = create_tool(
- self.framework, t_type, self._name, stage=self._stage,
**config
- )
-
# Load graphs from cache
- if cache_info.get("graphs"):
+ if not self._graphs and cache_info.get("graphs"):
self._graphs, self._weights = self._load_graphs(cache_dir,
cache_info["graphs"])
- self._logger.debug(
- "Load {} graphs from cache @ {}".format(len(self._graphs),
cache_dir)
- )
+ self._logger.info("Load %d graphs from %s", len(self._graphs),
cache_dir)
- # Get or rebuild graphs
- if build_graph or not self._graphs:
+ # Translate graphs from module
+ if not self._graphs:
self._graphs, self._weights = self._translate()
- self._logger.debug("Translate {} graphs from
module".format(len(self._graphs)))
+ self._logger.info("Translate %d graphs from module",
len(self._graphs))
- # reset graph for tools
- for tool in self._tools.values():
- self._graphs, self._weights = tool.reset(
- self._graphs, self._weights, cache_dir=cache_dir
- )
-
- if cache_info.get("model") and not build_graph:
- # Load model from cache
+ # Load model from cache
+ if not self._model and cache_info.get("model"):
+ self._graphs, self._weights = self.reset_tools(cache_dir=cache_dir)
self._model = self._load_model(cache_dir, cache_info["model"])
- else:
- # Generate model
+ self._logger.info("Load model(%s) from %s", self.framework,
cache_dir)
+
+ # Generate model
+ if not self._model:
+ # Generate normal model
+ self._graphs, self._weights = self.reset_tools(cache_dir=cache_dir)
self._model = self._generate_model()
- if "loader" in self._generate_config:
- loader, generate_config = self._generate_config["loader"]
- self._model = loader(self._model, **generate_config)
- self._logger.info(
- "Model({}) processed by customize loader {}({})".format(
- self.framework, loader, generate_config
- )
- )
+
+ # Log generate info
+ generate_msg = "Generate model({})".format(self.framework)
+ if self._tools:
+ self._logger.info("%s with tools: %s", generate_msg,
",".join(self._tools.keys()))
+ else:
+ self._logger.info("%s without tools", generate_msg)
+ if "generator" in self._generate_config:
+ generator, generate_config = self._generate_config["generator"]
+ self._model = generator(self._model, **generate_config)
+ self._logger.info("%s by %s(%s)", generate_msg, generator,
generate_config)
+
+ # Inspect model
self._model_info = self._inspect_model()
- if self._debug_level >= 3:
+ if self._debug_level >= 2:
self._logger.debug(msc_utils.msg_block("RUNNER.MODEL_INFO",
self._model_info))
- if cache_info.get("runnable") and not build_graph:
- # Load runnable from cache
+ runnable_msg = "runnable({}, {}) @ {}".format(
+ self.framework, "train" if self._is_training else "eval",
self._device
+ )
+
+ # Load runnable from cache
+ if not self._runnable and cache_info.get("runnable"):
self._runnable = self._load_runnable(cache_dir,
cache_info["runnable"])
- else:
- # Build runnable on device
+ self._logger.info("Load %s from %s", runnable_msg, cache_dir)
+
+ # Build runnable
+ if not self._runnable:
self._runnable = self._to_runnable(self._model, self._device,
self._is_training)
- self._logger.info(
- "Runnable({}, {}) loaded on device {}".format(
- self.framework, "train" if self._is_training else "eval",
self._device
- )
- )
+ self._logger.info("Build %s", runnable_msg)
return self._runnable
- def save_cache(self, cache_dir: msc_utils.MSCDirectory):
+ def save_cache(
+ self,
+ cache_dir: msc_utils.MSCDirectory,
+ save_model: bool = True,
+ save_runnable: bool = True,
+ save_tools: bool = True,
+ ):
"""Save runner to cache
Parameters
-------
cache_dir: MSCDirectory
cache path for save/load info
+ save_model: bool
+ Whether to save model.
+ save_runnable: bool
+ Whether to save runnable.
+ save_tools: bool
+ Whether to save tools.
"""
- cache_info = {
- "graphs": self._save_graphs(cache_dir),
- "model": self._save_model(cache_dir),
- "runnable": self._save_runnable(cache_dir),
- }
- for tool in self._tools.values():
- cache_info.update(tool.save_cache(cache_dir))
+ cache_info = {"graphs": self._save_graphs(cache_dir)}
+ if save_model:
+ cache_info["model"] = self._save_model(cache_dir)
+ if save_runnable:
+ cache_info["runnable"] = self._save_runnable(cache_dir)
+ if save_tools:
+ for t_type, tool in self._tools.items():
+ cache_info[t_type] = tool.save_cache(cache_dir)
with open(cache_dir.relpath("cache_info.json"), "w") as f:
f.write(json.dumps(cache_info, indent=2))
- if self._debug_level >= 3:
- self._logger.debug(
- msc_utils.msg_block("RUNNER.CACHE_INFO", {"folder": cache_dir,
"info": cache_info})
- )
+ self._logger.debug(
+ msc_utils.msg_block("RUNNER.SAVE_CACHE", {"folder": cache_dir,
"info": cache_info})
+ )
+
+ def reset_tools(
+ self,
+ graphs: List[MSCGraph] = None,
+ weights: List[Dict[str, tvm.nd.array]] = None,
+ tools: List[BaseTool] = None,
+ cache_dir: msc_utils.MSCDirectory = None,
+ ):
+ """Reset the tools
+
+ Parameters
+ -------
+ graphs: list<MSCgraph>
+ The msc graphs.
+ weights: list<dict<str, tvm.nd.array>>
+ The weights.
+ tools: list<BaseTool>
+ The tools.
+ cache_dir: MSCDirectory
+ cache path for save/load info.
+
+ Returns
+ -------
+ graphs: list<MSCgraph>
+ The msc graphs.
+ weights: list<dict<str, tvm.nd.array>>
+ The weights.
+ """
+
+ graphs = graphs or self._graphs
+ weights = weights or self._weights
+ tools = tools or self._tools.values()
+ for tool in tools:
+ graphs, weights = tool.reset(graphs, weights, cache_dir)
+ return graphs, weights
def run(
self, inputs: Union[List[np.ndarray], Dict[str, np.ndarray]],
ret_type="dict"
@@ -260,6 +318,8 @@ class BaseRunner(object):
), "Expected all inputs as np.ndarray"
inputs = {i["name"]: inputs[i["name"]] for i in model_inputs}
outputs = self._call_runnable(self._runnable, inputs, self._device)
+ if ret_type == "native":
+ return outputs
if ret_type == "dict":
if isinstance(outputs, (list, tuple)):
assert len(outputs) == len(
@@ -283,6 +343,22 @@ class BaseRunner(object):
outputs = [msc_utils.cast_array(data) for data in outputs]
return outputs
+ def get_tool_config(self, tool_type: str) -> dict:
+ """Get tool by type
+
+ Parameters
+ -------
+ tool_type: str
+ The type of the tool prune| quantize| distill...
+
+ Returns
+ -------
+ config: dict
+ The tool config.
+ """
+
+ return self._tools_config.get(tool_type)
+
def get_tool(self, tool_type: str) -> BaseTool:
"""Get tool by type
@@ -299,7 +375,21 @@ class BaseRunner(object):
return self._tools.get(tool_type)
- def apply_tool(self, tool_type: str, data_loader: Any = None) -> dict:
+ def get_tools(self) -> Iterable[BaseTool]:
+ """Get all saved tools by tag
+
+ Returns
+ -------
+ tools: iterable<BaseTool>
+ The saved tools.
+ """
+
+ for t_type in ToolType.all_types():
+ tool = self.get_tool(t_type)
+ if tool:
+ yield tool
+
+ def apply_tool(self, tool_type: str, data_loader: Any = None) -> str:
"""Execute tool and get plan
Parameters
@@ -308,6 +398,11 @@ class BaseRunner(object):
The tool type, should be in ToolType
data_loader:
The data loader
+
+ Returns
+ -------
+ plan_file: str
+ The saved plan file.
"""
assert tool_type in self._tools, "Can not find tool " + str(tool_type)
@@ -316,7 +411,7 @@ class BaseRunner(object):
if not pruner.finalize():
assert data_loader, "data_loader should be given to plan prune"
for inputs in data_loader():
- self.run(inputs)
+ self.run(inputs, ret_type="native")
break
plan = pruner.finalize()
else:
@@ -325,8 +420,28 @@ class BaseRunner(object):
plan_file = self._tools_config[tool_type]["plan_file"]
with open(plan_file, "w") as f:
f.write(json.dumps(plan, indent=2))
- self._logger.info("Save %s plan -> %s", tool_type, plan_file)
- return plan
+ self._logger.info("Save %d plan(%s) -> %s", len(plan), tool_type,
plan_file)
+ return plan_file
+
+ def _update_codegen(self, config: Dict[str, Any]):
+ """Update the codegen in generate_config
+
+ Parameters
+ -------
+ config: dict
+ The extra config for codegen.
+ """
+
+ if "codegen" not in self._generate_config:
+ self._generate_config["codegen"] = {}
+ codegen = self._generate_config["codegen"]
+ if isinstance(codegen, dict):
+ codegen.update(config)
+ elif isinstance(codegen, (list, tuple)):
+ for c in codegen:
+ c.update(config)
+ else:
+ raise TypeError("Unexpecet codegen config " + str(codegen))
def visualize(self, visual_dir: msc_utils.MSCDirectory):
"""Visualize MSCGraphs
@@ -371,8 +486,9 @@ class BaseRunner(object):
self._model = None
if self._runnable:
self._runnable = None
- for tool in self._tools.values():
+ for tool in self.get_tools():
tool.destory()
+ remove_tools(self._name)
def _translate(self) -> Tuple[List[MSCGraph], Dict[str, tvm.nd.array]]:
"""Translate IRModule to MSCgraphs
@@ -434,7 +550,7 @@ class BaseRunner(object):
-------
graphs: list<MSCgraph>
The msc graphs.
- weights: list<dic<str, tvm.nd.array>>
+ weights: list<dict<str, tvm.nd.array>>
The weights
Returns
@@ -579,10 +695,18 @@ class BaseRunner(object):
return True
+ @classmethod
+ def support_tool(cls, tool_type: str) -> bool:
+ return True
+
@property
def stage(self):
return self._stage
+ @property
+ def debug_level(self):
+ return self._debug_level
+
@property
def model(self):
return self._model
@@ -690,7 +814,7 @@ class ModelRunner(BaseRunner):
-------
graphs: list<MSCgraph>
The msc graphs.
- weights: list<dic<str, tvm.nd.array>>
+ weights: list<dict<str, tvm.nd.array>>
The weights
Returns
@@ -699,9 +823,11 @@ class ModelRunner(BaseRunner):
The runnable model
"""
+ graph = graphs[0] if graphs else self._graphs[0]
+ weight = weights[0] if weights else self._weights[0]
return self.codegen_func(
- graphs or self._graphs[0],
- weights or self._weights[0],
+ graph,
+ weight,
codegen_config=self._generate_config.get("codegen"),
print_config=self._generate_config.get("print"),
build_folder=self._generate_config["build_folder"],
@@ -853,7 +979,7 @@ class BYOCRunner(BaseRunner):
-------
graphs: list<MSCgraph>
The msc graphs.
- weights: list<dic<str, tvm.nd.array>>
+ weights: list<dict<str, tvm.nd.array>>
The weights
Returns
@@ -954,10 +1080,10 @@ class BYOCRunner(BaseRunner):
The inspected model info
"""
- if self._debug_level >= 3:
+ if self._debug_level >= 2:
for idx, graph in enumerate(self._graphs):
self._logger.debug(
- msc_utils.msg_block("RUNNER.GRAPH[{}].INFO".format(idx),
graph.inspect())
+ msc_utils.msg_block("GRAPH[{}].INFO".format(idx),
graph.inspect())
)
return self._byoc_graph.inspect()
diff --git a/python/tvm/contrib/msc/core/tools/__init__.py
b/python/tvm/contrib/msc/core/tools/__init__.py
index 3d60ce22c6..0524e4c823 100644
--- a/python/tvm/contrib/msc/core/tools/__init__.py
+++ b/python/tvm/contrib/msc/core/tools/__init__.py
@@ -19,3 +19,4 @@
from .tool import *
from .execute import *
from .prune import *
+from .track import *
diff --git a/python/tvm/contrib/msc/core/tools/prune/method.py
b/python/tvm/contrib/msc/core/tools/prune/method.py
index 6e294dc15c..fd3abe8df4 100644
--- a/python/tvm/contrib/msc/core/tools/prune/method.py
+++ b/python/tvm/contrib/msc/core/tools/prune/method.py
@@ -99,9 +99,9 @@ class PruneMethod(object):
return config
if len(in_indices) > 0:
data = cls.prune_axis(data, in_axis, in_indices)
- weight = pruner.find_tensor(name)
- left_num = int(((density * weight.dim_at(out_axis) + stride) //
stride) * stride)
- axis_sum = [np.abs(d).sum() for d in np.split(data,
data.shape[out_axis], out_axis)]
+ out_dim = data.shape[out_axis]
+ left_num = int(((density * out_dim + stride) // stride) * stride)
+ axis_sum = [np.abs(d).sum() for d in np.split(data, out_dim, out_axis)]
rank = np.argsort(np.array(axis_sum))
config["out_indices"] = rank[-left_num:].tolist()
return config
diff --git a/python/tvm/contrib/msc/core/tools/prune/pruner.py
b/python/tvm/contrib/msc/core/tools/prune/pruner.py
index 5fa625c2ad..577fe2bf4f 100644
--- a/python/tvm/contrib/msc/core/tools/prune/pruner.py
+++ b/python/tvm/contrib/msc/core/tools/prune/pruner.py
@@ -17,10 +17,11 @@
"""tvm.contrib.msc.core.tools.prune.pruner"""
from typing import List, Dict, Tuple, Any
+import numpy as np
import tvm
from tvm.contrib.msc.core.ir import MSCGraph, WeightJoint, MSCTensor
-from tvm.contrib.msc.core.tools.tool import ToolType, WeightTool, Strategy
+from tvm.contrib.msc.core.tools.tool import ToolType, WeightTool, ToolStrategy
from tvm.contrib.msc.core import _ffi_api
from tvm.contrib.msc.core import utils as msc_utils
from .method import PruneMethod
@@ -64,7 +65,7 @@ class BasePruner(WeightTool):
}
return main_wtypes, relation_wtypes
- def _parse_strategys(self, strategy_list: dict) -> Dict[str, Strategy]:
+ def _parse_strategys(self, strategy_list: dict) -> Dict[str, ToolStrategy]:
"""Parse the strategy to get valid strategy
Parameters
@@ -74,7 +75,7 @@ class BasePruner(WeightTool):
Returns
-------
- strategys: dict<str, Strategy>
+ strategys: dict<str, ToolStrategy>
The parsed strategy.
"""
@@ -85,10 +86,10 @@ class BasePruner(WeightTool):
return super()._parse_strategys([_update_stages(s) for s in
strategy_list])
- def load_graphs(
+ def _reset(
self, graphs: List[MSCGraph], weights: List[Dict[str, tvm.nd.array]]
) -> Tuple[List[MSCGraph], List[Dict[str, tvm.nd.array]]]:
- """Load the graphs and weights
+ """Reset the tool
Parameters
----------
@@ -105,10 +106,13 @@ class BasePruner(WeightTool):
The weights
"""
- graphs, weights = super().load_graphs(graphs, weights)
- if not self._plan:
- return graphs, weights
- return self.prune_graphs(graphs, weights)
+ self._meta_weights = {}
+ for sub_weights in weights:
+ self._meta_weights.update(sub_weights)
+ graphs, weights = super()._reset(graphs, weights)
+ if self._plan and self._enabled:
+ return self.prune_graphs(graphs, weights)
+ return graphs, weights
def _execute_before_build(self, *args, **kwargs):
"""Execute before model build
@@ -164,12 +168,10 @@ class BasePruner(WeightTool):
strategy = self._get_tensor_strategy(name, consumer)
if not strategy:
return False
- if strategy.get_config("density", 1.0) == 1.0:
- return False
return True
def _process_tensor(
- self, tensor: Any, name: str, consumer: str, scope: str, strategys:
List[Strategy]
+ self, tensor: Any, name: str, consumer: str, scope: str, strategys:
List[ToolStrategy]
) -> Any:
"""Process tensor
@@ -183,7 +185,7 @@ class BasePruner(WeightTool):
The name of the consumer.
scope: str
The scope mark teacher| student| null.
- strategys: list<Strategy>
+ strategys: list<ToolStrategy>
The strategys for the tensor.
Returns
@@ -215,7 +217,7 @@ class BasePruner(WeightTool):
}
return tensor
- def _prune_tensor(self, name: str, consumer: str, strategys:
List[Strategy]) -> Any:
+ def _prune_tensor(self, name: str, consumer: str, strategys:
List[ToolStrategy]) -> Any:
"""Prune tensor
Parameters
@@ -226,7 +228,7 @@ class BasePruner(WeightTool):
The name of the consumer.
scope: str
The scope mark teacher| student| null.
- strategys: list<Strategy>
+ strategys: list<ToolStrategy>
The strategys for the tensor.
"""
@@ -250,6 +252,8 @@ class BasePruner(WeightTool):
def _prunable(w_node: WeightJoint) -> bool:
"""Check if weight node is prunable"""
+ if strategy.get_config().get("density", 1) == 1:
+ return False
if w_node.get_attr("weight_strategy") != "main":
return False
if not w_node.children:
@@ -283,7 +287,7 @@ class BasePruner(WeightTool):
elif _prunable(w_node):
self._plan[w_node.name] = strategy(
self,
- self.get_data(w_node.name),
+ self.get_meta_data(w_node.name),
w_node.name,
consumer,
in_axis=in_axis,
@@ -333,8 +337,10 @@ class BasePruner(WeightTool):
pruned_tensors, pruned_weights = {}, {}
for node in graph.get_nodes():
for weight in node.get_weights().values():
- w_name = weight.name
- if w_name in self._plan and not
self._plan[w_name].get("pruned", False):
+ w_node, w_name = self.find_w_node(weight.name), weight.name
+ if w_name not in self._plan or w_node.get_attr("status",
"") == "pruned":
+ pruned_weights[w_name] = sub_weights[w_name]
+ else:
data = msc_utils.cast_array(sub_weights[w_name])
in_axis, out_axis =
self._get_io_axes(self.find_w_node(w_name))
w_config = self._plan[w_name]
@@ -344,23 +350,18 @@ class BasePruner(WeightTool):
data = PruneMethod.prune_axis(data, out_axis,
w_config["out_indices"])
pruned_tensors[w_name] = _prune_by_shape(weight,
data.shape)
pruned_weights[w_name] = tvm.nd.array(data)
- self._plan[w_name]["pruned"] = True
+ w_node.set_attr("status", "pruned")
pruned_weights_cnt += 1
- else:
- pruned_weights[w_name] = sub_weights[w_name]
- if node.optype == "constant" and node.weight_at("const").name
in pruned_tensors:
+ if node.optype == "constant":
+ if node.weight_at("const").name not in pruned_tensors:
+ continue
ref_tensor = pruned_tensors[node.weight_at("const").name]
- pruned_tensors[node.output_at(0).name] = MSCTensor(
- node.output_at(0).name,
- ref_tensor.dtype,
- ref_tensor.layout.name,
- ref_tensor.get_shape(),
- ref_tensor.alias,
+ pruned_tensors[node.output_at(0).name] = ref_tensor.clone(
+ name=node.output_at(0).name
)
- elif (
- node.optype in ("nn.conv2d", "msc.conv2d_bias",
"msc.linear", "msc.linear_bias")
- and node.weight_at("weight").name in pruned_tensors
- ):
+ elif node.optype in self._main_wtypes:
+ if node.weight_at("weight").name not in pruned_tensors:
+ continue
out = node.output_at(0)
if node.optype in ("msc.linear", "msc.linear_bias"):
channel_axis = out.ndim - 1
@@ -371,48 +372,82 @@ class BasePruner(WeightTool):
pruned_tensors[node.weight_at("weight").name].dim_at("O"),
channel_axis,
)
- else:
+ elif node.optype in self._relation_wtypes:
for out in node.get_outputs():
- if out.name in self._plan and not
self._plan[out.name].get("pruned", False):
- pruned_tensors[out.name] = _prune_by_channel(
- out, len(self._plan[out.name]["out_indices"])
- )
- self._plan[out.name]["pruned"] = True
- elif (
- node.get_inputs()
- and node.input_at(0).name in pruned_tensors
- and node.input_at(0).layout_of("C") >= 0
- and out.layout_of("C") >= 0
- ):
- pruned_tensors[out.name] = _prune_by_channel(
- out,
pruned_tensors[node.input_at(0).name].dim_at("C")
- )
+ w_node = self.find_w_node(out.name)
+ if out.name not in self._plan or
w_node.get_attr("status", "") == "pruned":
+ continue
+ pruned_tensors[out.name] = _prune_by_channel(
+ out, len(self._plan[out.name]["out_indices"])
+ )
+ w_node.set_attr("status", "pruned")
+ elif node.get_inputs():
+ ref_input = node.input_at(0)
+ if ref_input.name not in pruned_tensors or
ref_input.layout_of("C") < 0:
+ continue
+ for out in node.get_outputs():
+ if out.layout_of("C") < 0:
+ continue
+ pruned_tensors[out.name] = _prune_by_channel(
+ out, pruned_tensors[ref_input.name].dim_at("C")
+ )
+
+ def _is_pruned(tensor: MSCTensor, graph: MSCGraph) -> bool:
+ return tensor.get_shape() !=
graph.find_tensor(tensor.name).get_shape()
+
+ pruned_tensors = {k: v for k, v in pruned_tensors.items() if
_is_pruned(v, graph)}
if self.on_debug(3, in_forward=False):
self._logger.debug(msc_utils.msg_block("Pruned Tensors",
pruned_tensors))
- pruned_graph = _ffi_api.PruneWeights(graph, pruned_tensors)
- new_graphs.append(pruned_graph)
+
+ if pruned_tensors:
+ pruned_graph = _ffi_api.PruneWeights(graph, pruned_tensors)
+ new_graphs.append(pruned_graph)
+ else:
+ new_graphs.append(graph)
new_weights.append(pruned_weights)
- # log compress rate
def _flatten_size(weights):
weight_size = 0
for sub_weights in weights:
for w_data in sub_weights.values():
weight_size += w_data.asnumpy().size
- return weight_size
+ return weight_size / 2**20
raw_size = _flatten_size(weights)
- new_size = _flatten_size(new_weights)
- self._logger.info(
- "Prune {} weights, compress to {:g}% ({:g} M->{:g} M)".format(
+ # log compress rate
+ if pruned_weights_cnt > 0:
+ new_size = _flatten_size(new_weights)
+ self._logger.info(
+ "Prune %d weights, compress to %.2f%% (%.4f M->%.4f M)",
pruned_weights_cnt,
new_size * 100 / raw_size,
- raw_size / 2**20,
- new_size / 2**20,
+ raw_size,
+ new_size,
)
- )
+ else:
+ self._logger.info("No weights pruned, size %.4f M", raw_size)
return new_graphs, new_weights
+ def get_meta_data(self, name: str) -> np.ndarray:
+ """Get meta weight as np.ndarray
+
+ Parameters
+ ----------
+ name: str
+ The name of data.
+
+ Returns
+ -------
+ data: np.ndarray
+ The data in np.ndarray format.
+ """
+
+ if name in self._meta_weights:
+ return msc_utils.cast_array(self._meta_weights[name])
+ raise Exception(
+ "Can not find data {} from {} weights".format(name,
len(self._meta_weights))
+ )
+
def finalize(self) -> dict:
"""Get the plan"""
diff --git a/python/tvm/contrib/msc/core/tools/tool.py
b/python/tvm/contrib/msc/core/tools/tool.py
index c37ec3db97..480705f31b 100644
--- a/python/tvm/contrib/msc/core/tools/tool.py
+++ b/python/tvm/contrib/msc/core/tools/tool.py
@@ -54,7 +54,7 @@ class ToolScope(object):
STUDENT = "student"
-class Executor(object):
+class ToolExecutor(object):
"""Executor for process the tensor
Parameters
@@ -94,11 +94,6 @@ class Executor(object):
kwargs.update({k: v for k, v in self._config.items() if k not in
kwargs})
return self._method(*args, **kwargs)
- def get_config(self, key: str, default: Any) -> Any:
- """Get the value in config"""
-
- return self._config.get(key, default)
-
def copy(self, name: str = None, method: callable = None, config: dict =
None):
"""Copy a executor
@@ -113,20 +108,24 @@ class Executor(object):
Returns
-------
- new_strategy: Strategy
- The copied strategy
+ new_executor: ToolExecutor
+ The copied executor
"""
new_config = config or {}
new_config.update({k: v for k, v in self._config.items() if k not in
new_config})
- return Executor(name or self._name, method or self._method, new_config)
+ return ToolExecutor(name or self._name, method or self._method,
new_config)
@property
def name(self):
return self._name
+ @property
+ def config(self):
+ return self._config
+
-class Strategy(object):
+class ToolStrategy(object):
"""Strategy for process tensor
Parameters
@@ -137,13 +136,16 @@ class Strategy(object):
The tensor type.
stage: str
The init stage
+ meta: dict:
+ The meta strategy config.
"""
- def __init__(self, name: str, tensor_type: str, stage: str = "default"):
+ def __init__(self, name: str, tensor_type: str, stage: str = "default",
meta: dict = None):
self._name = name
self._tensor_type = tensor_type
self._stage = stage
self._executors = {}
+ self._meta = meta
def __str__(self):
return "{}({} @ {}) ".format(self._name, self._tensor_type,
self._stage) + "; ".join(
@@ -187,14 +189,14 @@ class Strategy(object):
self._stage = stage
- def add_executor(self, stage: str, executor: Executor):
+ def add_executor(self, stage: str, executor: ToolExecutor):
"""Add a executor to strategy
Parameters
----------
stage: str
The mark of the executor.
- executor: Executor
+ executor: ToolExecutor
The executor to process tensor.
"""
@@ -215,10 +217,10 @@ class Strategy(object):
return self._executors[self._stage]
return self._executors["default"]
- def get_config(self, key: str, default: Any) -> Any:
- """Get the value in config"""
+ def get_config(self) -> dict:
+ """Get the config of current executor"""
- return self.get_executor().get_config(key, default)
+ return self.get_executor().config
def support_stage(self, stage: str) -> bool:
"""Check if the strategy support a stage
@@ -258,12 +260,12 @@ class Strategy(object):
Returns
-------
- new_strategy: Strategy
+ new_strategy: ToolStrategy
The copied strategy
"""
configs = configs or {}
- strategy = Strategy(
+ strategy = ToolStrategy(
name or self._name, tensor_type or self._tensor_type, stage or
self._stage
)
for st_name, executor in self._executors.items():
@@ -271,6 +273,10 @@ class Strategy(object):
strategy.add_executor(st_name, new_executor)
return strategy
+ @property
+ def meta(self):
+ return self._meta
+
class BaseTool(object):
"""Basic tool of MSC
@@ -299,7 +305,7 @@ class BaseTool(object):
self,
stage: str,
plan_file: str,
- strategys: dict,
+ strategys: List[dict],
cache_processed: bool = True,
options: dict = None,
debug_level: int = 0,
@@ -320,9 +326,8 @@ class BaseTool(object):
title = "{}.SETUP({} @ {})".format(self.tool_type().upper(),
self._stage, self.framework())
self._logger.info(msc_utils.msg_block(title, self.setup(), width=0))
if self._debug_level >= 3 and self._plan:
- self._logger.debug(
-
msc_utils.msg_block("{}.PLAN".format(self.tool_type().upper()), self._plan)
- )
+ title = "{}.PLAN".format(self.tool_type().upper())
+ self._logger.debug(msc_utils.msg_block(title, self._plan))
def setup(self) -> dict:
"""Setup the tool
@@ -348,58 +353,62 @@ class BaseTool(object):
"debug_level": self._debug_level,
}
- def _parse_strategys(self, strategy_list: dict) -> Dict[str, Strategy]:
+ def _parse_strategys(self, strategy_list: List[dict]) -> Dict[str,
ToolStrategy]:
"""Parse the strategy to get valid strategy
Parameters
-------
- strategy_list: dict
- The given strategy
+ strategy_list: list<dict>
+ The given strategys
Returns
-------
- strategys: dict<str, Strategy>
+ strategys: dict<str, ToolStrategy>
The parsed strategy.
"""
strategys = {}
assert isinstance(strategy_list, list) and all(
isinstance(s, dict) for s in strategy_list
- ), "Strategy should be given as list of dict"
- for stra in strategy_list:
- method_cls_name = stra.pop("method_cls") if "method_cls" in stra
else "default"
+ ), "ToolStrategy should be given as list of dict"
+ for strategy in strategy_list:
+ meta_strategy = msc_utils.copy_dict(strategy)
+ method_cls_name = strategy.pop("method_cls") if "method_cls" in
strategy else "default"
method_cls = msc_utils.get_registered_tool_method(
self.framework(), self.tool_type(), method_cls_name
)
- method_name = stra.pop("method") if "method" in stra else "default"
+ method_name = strategy.pop("method") if "method" in strategy else
"default"
+ method = None
if hasattr(method_cls, method_name):
method = getattr(method_cls, method_name)
- else:
+ if not method:
default_cls = msc_utils.get_registered_tool_method(
MSCFramework.MSC, self.tool_type(), method_cls_name
)
- assert hasattr(
- default_cls, method_name
- ), "Can not find method {} from neighter {} nor {}".format(
- method_name, method_cls, default_cls
- )
- method = getattr(default_cls, method_name)
- tensor_types = stra.pop("tensor_types") if "tensor_types" in stra
else ["all"]
- if "op_types" in stra:
- op_types = stra.pop("op_types")
+ if hasattr(default_cls, method_name):
+ method = getattr(default_cls, method_name)
+ if not method:
+ method = msc_utils.get_registered_func(method_name)
+ assert method, "Can not find method with " + str(method_name)
+ tensor_types = strategy.pop("tensor_types") if "tensor_types" in
strategy else ["all"]
+ if "op_types" in strategy:
+ op_types = strategy.pop("op_types")
marks = [("{}.{}".format(s, t), t) for s, t in
product(op_types, tensor_types)]
- elif "op_names" in stra:
- op_names = stra.pop("op_names")
+ elif "op_names" in strategy:
+ op_names = strategy.pop("op_names")
marks = [("{}.{}".format(s, t), t) for s, t in
product(op_names, tensor_types)]
+ elif "tensor_names" in strategy:
+ tensor_names = strategy.pop("tensor_names")
+ marks = [(n, "all") for n in tensor_names]
else:
marks = [("default", "all")]
- stages = stra.pop("stages") if "stages" in stra else ["default"]
+ stages = strategy.pop("stages") if "stages" in strategy else
["default"]
for mark, t_type in marks:
if mark not in strategys:
- strategys[mark] = Strategy(mark, t_type, self._stage)
+ strategys[mark] = ToolStrategy(mark, t_type, self._stage,
meta_strategy)
for stage in stages:
strategys[mark].add_executor(
- stage, Executor(method_name, method,
copy.deepcopy(stra))
+ stage, ToolExecutor(method_name, method,
copy.deepcopy(strategy))
)
return strategys
@@ -436,41 +445,22 @@ class BaseTool(object):
cache_info = {}
if self.tool_type() in cache_info:
self.load_cache(cache_dir, cache_info[self.tool_type()])
- else:
- graphs, weights = self.load_graphs(graphs, weights)
- self._graphs, self._weights = graphs, {}
+ self._graphs, weights = self._reset(graphs, weights)
+ self._weights = {}
for sub_weights in weights:
self._weights.update(sub_weights)
self._logger.debug(
- "%s load %d graphs and %d weights",
+ "%s reset %d graphs, %d weights",
self.tool_type(),
len(self._graphs),
len(self._weights),
)
- self._reset()
return self._graphs, weights
- def _reset(self):
- """Extra reset for tool"""
-
- return None
-
- def change_stage(self, stage: str):
- """Change the stage of tools and strategy"""
-
- self._stage = stage
- for strategy in self._strategys.values():
- strategy.change_stage(stage)
-
- def destory(self):
- """Destory tool"""
-
- self._graphs, self._weights = [], {}
-
- def load_graphs(
+ def _reset(
self, graphs: List[MSCGraph], weights: List[Dict[str, tvm.nd.array]]
) -> Tuple[List[MSCGraph], List[Dict[str, tvm.nd.array]]]:
- """Load the graphs and weights
+ """Reset the tool
Parameters
----------
@@ -489,6 +479,23 @@ class BaseTool(object):
return graphs, weights
+ def change_stage(self, stage: str):
+ """Change the stage of tool and strategy"""
+
+ self._stage = stage
+ for strategy in self._strategys.values():
+ strategy.change_stage(stage)
+
+ def change_logger(self, logger: logging.Logger):
+ """Change the logger of tool"""
+
+ self._logger = logger
+
+ def destory(self):
+ """Destory tool"""
+
+ self._graphs, self._weights = [], {}
+
def load_cache(self, cache_dir: msc_utils.MSCDirectory, cache_info: dict):
"""Save runner to cache
@@ -677,6 +684,8 @@ class BaseTool(object):
The processed tensor.
"""
+ if not self._enabled:
+ return tensor
if not self._support_scope(scope):
return tensor
strategys = self._get_tensor_strategys(name, consumer)
@@ -780,7 +789,7 @@ class BaseTool(object):
return len(strategys) > 0
def _process_tensor(
- self, tensor: Any, name: str, consumer: str, scope: str, strategys:
List[Strategy]
+ self, tensor: Any, name: str, consumer: str, scope: str, strategys:
List[ToolStrategy]
) -> Any:
"""Process tensor
@@ -794,7 +803,7 @@ class BaseTool(object):
The name of the consumer.
scope: str
The scope mark teacher| student| null.
- strategys: list<Strategy>
+ strategys: list<ToolStrategy>
The strategys for the tensor.
Returns
@@ -832,8 +841,8 @@ class BaseTool(object):
return None
- def update_plan(self, plan: dict):
- """Update the plan
+ def set_plan(self, plan: dict):
+ """Set the plan
Parameters
----------
@@ -841,23 +850,10 @@ class BaseTool(object):
The new plan.
"""
- self._plan.update(plan)
-
- def get_plan(self, name: str) -> dict:
- """Get the plan for name
-
- Parameters
- ----------
- name: str
- The plan name.
-
- Returns
- -------
- plan: dict
- The plan of the name.
- """
-
- return self._plan.get(name, {})
+ if self._plan:
+ self._plan = msc_utils.update_dict(self._plan, plan)
+ else:
+ self._plan = plan
def finalize(self) -> dict:
"""Get the plan"""
@@ -1177,7 +1173,7 @@ class BaseTool(object):
return None
return self._tensor_cache[tensor_id].get(key)
- def _get_tensor_strategys(self, name: str, consumer: str) ->
List[Strategy]:
+ def _get_tensor_strategys(self, name: str, consumer: str) ->
List[ToolStrategy]:
"""Get the strategys by name and consumer
Parameters
@@ -1189,7 +1185,7 @@ class BaseTool(object):
Returns
-------
- strategys: list<Strategy>
+ strategys: list<ToolStrategy>
The strategys for the tensor.
"""
@@ -1222,16 +1218,20 @@ class BaseTool(object):
consumer.optype + ".all",
]
strategys = []
- for n in name_refs:
- if n in self._strategys and
self._strategys[n].support_stage(self._stage):
- strategys.append(self._strategys[n])
+ tensor_strategy = self._strategys.get(tensor_id)
+ if tensor_strategy and tensor_strategy.support_stage(self._stage):
+ strategys.append(tensor_strategy)
+ if not strategys:
+ for n in name_refs:
+ if n in self._strategys and
self._strategys[n].support_stage(self._stage):
+ strategys.append(self._strategys[n])
d_strategy = self._strategys.get("default")
if not strategys and d_strategy and
d_strategy.support_stage(self._stage):
strategys.append(d_strategy)
self._save_tensor_cache(name, consumer, mark, strategys)
return self._get_tensor_cache(name, consumer, mark)
- def _get_tensor_strategy(self, name: str, consumer: str) -> Strategy:
+ def _get_tensor_strategy(self, name: str, consumer: str) -> ToolStrategy:
"""Get the unique strategy by name and consumer
Parameters
@@ -1243,7 +1243,7 @@ class BaseTool(object):
Returns
-------
- strategy: Strategy
+ strategy: ToolStrategy
The unique strategy for the tensor.
"""
@@ -1274,26 +1274,22 @@ class BaseTool(object):
class WeightTool(BaseTool):
"""Basic tool with weight graphs"""
- def _reset(self):
- """Extra reset for tool"""
+ def setup(self) -> dict:
+ """Setup the tool
- super()._reset()
- assert len(self._graphs) == len(
- self._weight_graphs
- ), "Graphs {} mismatch with weight graphs {}".format(
- len(self._graphs), len(self._weight_graphs)
- )
- self._logger.debug("%s load %d weight graphs", self.tool_type(),
len(self._weight_graphs))
- if self.on_debug(2, in_forward=False):
- for idx, graph in enumerate(self._weight_graphs):
- self._logger.debug(
- msc_utils.msg_block("WEIGHT_GRAPH[{}].INFO".format(idx),
graph.inspect())
- )
+ Returns
+ -------
+ info: dict
+ The setup info.
+ """
- def load_graphs(
+ self._weight_graphs = []
+ return super().setup()
+
+ def _reset(
self, graphs: List[MSCGraph], weights: List[Dict[str, tvm.nd.array]]
) -> Tuple[List[MSCGraph], List[Dict[str, tvm.nd.array]]]:
- """Load the graphs and weights
+ """Reset the tool
Parameters
----------
@@ -1312,12 +1308,28 @@ class WeightTool(BaseTool):
The weights
"""
- graphs, weights = super().load_graphs(graphs, weights)
- main_wtypes, relation_wtypes = self._get_wtypes()
- assert main_wtypes, "main_wtypes should be given to build weight
graphs"
- self._weight_graphs = [
- _ffi_api.WeightGraph(graph, main_wtypes, relation_wtypes) for
graph in graphs
- ]
+ graphs, weights = super()._reset(graphs, weights)
+ self._main_wtypes, self._relation_wtypes = self._get_wtypes()
+ assert self._main_wtypes, "main_wtypes should be given to build weight
graphs"
+ if self._weight_graphs:
+ assert len(graphs) == len(
+ self._weight_graphs
+ ), "Graphs {} mismatch with weight graphs {}".format(
+ len(graphs), len(self._weight_graphs)
+ )
+ else:
+ self._weight_graphs = [
+ _ffi_api.WeightGraph(graph, self._main_wtypes,
self._relation_wtypes)
+ for graph in graphs
+ ]
+ self._logger.debug(
+ "%s reset %d weight graphs", self.tool_type(),
len(self._weight_graphs)
+ )
+ if self.on_debug(2, in_forward=False):
+ for idx, graph in enumerate(self._weight_graphs):
+ self._logger.debug(
+ msc_utils.msg_block("WEIGHT_GRAPH[{}].INFO".format(idx),
graph.inspect())
+ )
return graphs, weights
def _get_wtypes(self) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
@@ -1350,6 +1362,12 @@ class WeightTool(BaseTool):
self._weight_graphs = [
WeightGraph.from_json(cache_dir.relpath(f)) for f in
cache_info["weight_graphs"]
]
+ self._logger.debug(
+ "%s load %d weight graphs from %s",
+ self.tool_type(),
+ len(self._weight_graphs),
+ cache_dir,
+ )
def save_cache(self, cache_dir: msc_utils.MSCDirectory) -> dict:
"""Save runner to cache
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/core/tools/track/__init__.py
similarity index 90%
copy from python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
copy to python/tvm/contrib/msc/core/tools/track/__init__.py
index 94e19b7e07..2c82a6d486 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/core/tools/track/__init__.py
@@ -14,6 +14,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-"""tvm.contrib.msc.framework.tensorflow.tools"""
+"""tvm.contrib.msc.core.tools.track"""
-from .prune import *
+from .tracker import *
+from .method import *
diff --git a/python/tvm/contrib/msc/core/tools/track/method.py
b/python/tvm/contrib/msc/core/tools/track/method.py
new file mode 100644
index 0000000000..aaa07b3812
--- /dev/null
+++ b/python/tvm/contrib/msc/core/tools/track/method.py
@@ -0,0 +1,102 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# pylint: disable=unused-argument
+"""tvm.contrib.msc.core.tools.track.method"""
+
+from typing import List, Dict
+import numpy as np
+
+from tvm.contrib.msc.core.tools.tool import ToolType, BaseTool
+from tvm.contrib.msc.core.utils.namespace import MSCFramework
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class TrackMethod(object):
+ """Default track method"""
+
+ @classmethod
+ def save_compared(
+ cls,
+ tracker: BaseTool,
+ data: np.ndarray,
+ name: str,
+ consumer: str,
+ compare_to: Dict[str, List[str]],
+ ) -> np.ndarray:
+ """Compare and save the data
+
+ Parameters
+ ----------
+ tracker: BaseTracker
+ The tracker
+ data: np.ndarray
+ The source data.
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+ stage: str
+ The current stage of tool.
+ compare_to: dict
+ The compare config
+ dataset: MSCDirectory
+ The root dir
+
+ Returns
+ -------
+ plan: dict
+ The plan of the tensor.
+ """
+
+ data = msc_utils.cast_array(data)
+ config = {"info": msc_utils.inspect_array(data)}
+ # save the data
+ tracker._saver.save_datas({name: data}, tracker._forward_cnt)
+ tracker.debug_tensor(data, name, consumer, "save")
+ # compare datas
+ if tracker._stage in compare_to:
+ diffs = {}
+ for stage in compare_to[tracker._stage]:
+ if stage in tracker._loaders:
+ if not tracker._loaders[stage].has_data(name,
tracker._forward_cnt):
+ continue
+ golden = tracker._loaders[stage].load_data(name,
tracker._forward_cnt)
+ report = msc_utils.compare_arrays({name: golden}, {name:
data})
+ diff_msg = "{}diff to {} -> {}".format(
+ tracker.msg_mark(), stage, report["info"][name]
+ )
+ if report["passed"] == 0:
+ tracker._logger.info(diff_msg)
+ elif tracker.on_debug(3):
+ tracker._logger.debug(diff_msg)
+ diffs[stage] = {
+ "pass": report["passed"] == 1,
+ "info": msc_utils.inspect_array(np.abs(golden - data)),
+ }
+ config["diffs"] = diffs
+ return config
+
+ @classmethod
+ def framework(cls):
+ return MSCFramework.MSC
+
+ @classmethod
+ def tool_type(cls):
+ return ToolType.TRACKER
+
+
+msc_utils.register_tool_method(TrackMethod)
diff --git a/python/tvm/contrib/msc/core/tools/track/tracker.py
b/python/tvm/contrib/msc/core/tools/track/tracker.py
new file mode 100644
index 0000000000..442ac6f508
--- /dev/null
+++ b/python/tvm/contrib/msc/core/tools/track/tracker.py
@@ -0,0 +1,185 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""tvm.contrib.msc.core.tools.track.tracker"""
+
+from typing import Any, List
+from tvm.contrib.msc.core.tools.tool import ToolType, BaseTool, ToolStrategy
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class BaseTracker(BaseTool):
+ """Base tracker for all"""
+
+ def setup(self) -> dict:
+ """Setup the tool
+
+ Returns
+ -------
+ info: dict
+ The setup info.
+ """
+
+ data_folder = msc_utils.get_dataset_dir().create_dir("Track")
+ self._loaders = {}
+ for folder in data_folder.listdir():
+ if msc_utils.is_simple_dataset(data_folder.relpath(folder)):
+ self._loaders[folder] =
msc_utils.SimpleDataLoader(data_folder.relpath(folder))
+ self._saver =
msc_utils.SimpleDataSaver(data_folder.relpath(self._stage))
+ self._max_iter = self._options.get("max_iter", 1)
+ info = super().setup()
+ info.update({"saver": self._saver, "loaders": self._loaders})
+ return info
+
+ def finalize(self) -> dict:
+ """Get the plan"""
+
+ self._saver.finalize()
+ return super().finalize()
+
+ def _execute_after_forward(self, output: Any) -> Any:
+ """Execute after model forward
+
+ Parameters
+ ----------
+ output: Any
+ The output reference of the model.
+
+ Returns
+ -------
+ output: Any
+ The modified output reference.
+ """
+
+ if self._forward_cnt < self._max_iter:
+ passed = {}
+ for info in self._plan.values():
+ if "diffs" not in info[self._stage]:
+ continue
+ for stage, p_info in info[self._stage]["diffs"].items():
+ if stage not in passed:
+ passed[stage] = {"total": 0, "passed": 0}
+ passed[stage]["total"] += 1
+ if p_info["pass"]:
+ passed[stage]["passed"] += 1
+ msg = "Track({})[{}] {} datas".format(self._stage,
self._forward_cnt, len(self._plan))
+ if passed:
+ msg += ", passed -> "
+ msg += "; ".join(
+ ["{}: {}/{}".format(s, i["passed"], i["total"]) for s, i
in passed.items()]
+ )
+ self._logger.info(msg)
+ return output
+
+ def _check_tensor(self, name: str, consumer: str) -> bool:
+ """Check if the tensor should be processed
+
+ Parameters
+ -------
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+
+ Returns
+ -------
+ vaild: bool
+ Whether to process the tensor.
+ """
+
+ if self._forward_cnt >= self._max_iter:
+ return False
+ strategy = self._get_tensor_strategy(name, consumer)
+ if not strategy:
+ return False
+ compare_to = strategy.get_config().get("compare_to", {})
+ if self._stage in compare_to:
+ return True
+ for stages in compare_to.values():
+ if self._stage in stages:
+ return True
+ return False
+
+ def _process_tensor(
+ self, tensor: Any, name: str, consumer: str, scope: str, strategys:
List[ToolStrategy]
+ ) -> Any:
+ """Process tensor
+
+ Parameters
+ -------
+ tensor: Any
+ Tensor in framework
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+ scope: str
+ The scope mark teacher| student| null.
+ strategys: list<ToolStrategy>
+ The strategys for the tensor.
+
+ Returns
+ -------
+ tensor: Any
+ The processed tensor.
+ """
+
+ return self._track_tensor(tensor, name, consumer, strategys)
+
+ def _track_tensor(
+ self, tensor: Any, name: str, consumer: str, strategys:
List[ToolStrategy]
+ ) -> Any:
+ """Process tensor
+
+ Parameters
+ -------
+ tensor: Any
+ Tensor in framework
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+ strategys: list<ToolStrategy>
+ The strategys for the tensor.
+
+ Returns
+ -------
+ tensor: Any
+ The processed tensor.
+ """
+
+ if self._stage in self._plan.get(name, {}):
+ return tensor
+ if name not in self._plan:
+ self._plan[name] = {}
+ plan = {}
+ for strategy in strategys:
+ plan.update(strategy(self, tensor, name, consumer))
+ self._plan[name][self._stage] = plan
+ return tensor
+
+ @classmethod
+ def tool_type(cls):
+ return ToolType.TRACKER
+
+
+class DefaultTracker(BaseTracker):
+ @classmethod
+ def tool_style(cls):
+ return "default"
+
+
+msc_utils.register_tool_cls(DefaultTracker)
diff --git a/python/tvm/contrib/msc/core/utils/info.py
b/python/tvm/contrib/msc/core/utils/info.py
index 782be26049..440789f856 100644
--- a/python/tvm/contrib/msc/core/utils/info.py
+++ b/python/tvm/contrib/msc/core/utils/info.py
@@ -238,6 +238,40 @@ def load_dict(str_dict: str, flavor: str = "json") -> dict:
return dict_obj
+def update_dict(
+ src_dict: dict, new_dict: dict, recursive: bool = True, soft_update: bool
= True
+) -> dict:
+ """Update src_dict with new_dict.
+
+ Parameters
+ ----------
+ src_dict: dict
+ The source dict.
+ new_dict: dict
+ The new dict.
+ recursive: bool
+ Whether to update the dict recursive.
+ soft_update: bool
+ Whether to update the source dict, False to force update.
+
+ Returns
+ -------
+ dict_obj: dict
+ The updated dict.
+ """
+
+ assert isinstance(src_dict, dict) and isinstance(
+ new_dict, dict
+ ), "update_dict only support dict, get src {} and new
{}".format(type(src_dict), type(new_dict))
+ for k, v in new_dict.items():
+ if isinstance(v, dict):
+ v = update_dict(src_dict.get(k, {}), v, recursive, soft_update)
+ src_dict[k] = v
+ elif not soft_update or k not in src_dict:
+ src_dict[k] = v
+ return src_dict
+
+
def dump_dict(dict_obj: dict, flavor: str = "dmlc") -> str:
"""Dump the config to string.
@@ -288,7 +322,8 @@ def dump_dict(dict_obj: dict, flavor: str = "dmlc") -> str:
lines.append("{}{}: {}".format(indent * " ", k, v))
return lines
- return "\n".join(_get_lines(dict_obj))
+ lines = _get_lines(dict_obj) or [" {}: {}".format(k, v) for k, v in
dict_obj.items()]
+ return "\n".join(lines)
return json.dumps(dict_obj)
diff --git a/python/tvm/contrib/msc/core/utils/log.py
b/python/tvm/contrib/msc/core/utils/log.py
index 525f1706f9..a406db806a 100644
--- a/python/tvm/contrib/msc/core/utils/log.py
+++ b/python/tvm/contrib/msc/core/utils/log.py
@@ -52,7 +52,7 @@ class IOLogger(object):
raise Exception(msg)
-def create_file_logger(level=logging.INFO, path: str = None) -> logging.Logger:
+def create_file_logger(level: Union[str, int] = logging.INFO, path: str =
None) -> logging.Logger:
"""Create file logger
Parameters
@@ -68,6 +68,16 @@ def create_file_logger(level=logging.INFO, path: str = None)
-> logging.Logger:
The logger.
"""
+ if isinstance(level, str):
+ if level == "debug":
+ level = logging.DEBUG
+ elif level == "info":
+ level = logging.INFO
+ elif level == "warn":
+ level = logging.WARN
+ else:
+ raise Exception("Unexcept verbose {}, should be debug| info| warn")
+
path = path or os.path.join(get_workspace(), "MSC_LOG")
log_name = os.path.basename(path)
logger = logging.getLogger(log_name)
@@ -104,15 +114,6 @@ def set_global_logger(level: Union[str, int] =
logging.INFO, path: str = None) -
The logger.
"""
- if isinstance(level, str):
- if level == "debug":
- level = logging.DEBUG
- elif level == "info":
- level = logging.INFO
- elif level == "warn":
- level = logging.WARN
- else:
- raise Exception("Unexcept verbose {}, should be debug| info| warn")
logger = create_file_logger(level, path)
MSCMap.set(MSCKey.GLOBALE_LOGGER, logger)
return logger
diff --git a/python/tvm/contrib/msc/core/utils/message.py
b/python/tvm/contrib/msc/core/utils/message.py
index 69c31c807e..4f93d402a0 100644
--- a/python/tvm/contrib/msc/core/utils/message.py
+++ b/python/tvm/contrib/msc/core/utils/message.py
@@ -124,6 +124,29 @@ def get_duration() -> dict:
return duration
+def msg_table(title: str, msg: str, width: int = 100):
+ """Log message in table format
+
+ Parameters
+ ----------
+ title: str
+ The title of the block
+ msg: str
+ The message to log.
+ width: int
+ The max width of block message
+
+ Returns
+ -------
+ msg: str
+ The block message.
+ """
+
+ if isinstance(msg, dict):
+ msg = dump_dict(msg, "table:" + str(width))
+ return "\n{0} {1} {0}\n{2}\n".format("-" * 20, title.center(40), msg)
+
+
def msg_block(title: str, msg: str, width: int = 100):
"""Log message in block format
diff --git a/python/tvm/contrib/msc/framework/tensorflow/runtime/runner.py
b/python/tvm/contrib/msc/framework/tensorflow/runtime/runner.py
index c686647bfe..4617c5d351 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/runtime/runner.py
+++ b/python/tvm/contrib/msc/framework/tensorflow/runtime/runner.py
@@ -93,7 +93,7 @@ class TensorflowRunner(ModelRunner):
-------
graphs: list<MSCgraph>
The msc graphs.
- weights: list<dic<str, tvm.nd.array>>
+ weights: list<dict<str, tvm.nd.array>>
The weights
Returns
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
index 94e19b7e07..d25cfd4e67 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
@@ -17,3 +17,4 @@
"""tvm.contrib.msc.framework.tensorflow.tools"""
from .prune import *
+from .track import *
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/framework/tensorflow/tools/track/__init__.py
similarity index 90%
copy from python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
copy to python/tvm/contrib/msc/framework/tensorflow/tools/track/__init__.py
index 94e19b7e07..e8787fb666 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tensorflow/tools/track/__init__.py
@@ -14,6 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-"""tvm.contrib.msc.framework.tensorflow.tools"""
+"""tvm.contrib.msc.framework.tensorflow.tools.track"""
-from .prune import *
+from .tracker import *
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/track/tracker.py
b/python/tvm/contrib/msc/framework/tensorflow/tools/track/tracker.py
new file mode 100644
index 0000000000..7023322681
--- /dev/null
+++ b/python/tvm/contrib/msc/framework/tensorflow/tools/track/tracker.py
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""tvm.contrib.msc.framework.tensorflow.tools.track.tracker"""
+
+from tvm.contrib.msc.core.tools.tool import ToolType
+from tvm.contrib.msc.core.tools.track import BaseTracker
+from tvm.contrib.msc.core.utils.namespace import MSCFramework
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class TensorflowTrackerFactory(object):
+ """Tracker factory for tensorflow"""
+
+ def create(self, base_cls: BaseTracker) -> BaseTracker:
+ """Create adaptive tracker
+
+ Parameters
+ ----------
+ base_cls: BaseTracker
+ The base tracker class
+
+ Returns
+ -------
+ tracker_cls: BaseTracker
+ The tracker class.
+ """
+
+ class Tracker(base_cls):
+ """Adaptive tracker for tensorflow"""
+
+ @classmethod
+ def framework(cls):
+ return MSCFramework.TENSORFLOW
+
+ return Tracker
+
+
+factory = TensorflowTrackerFactory()
+tools = msc_utils.get_registered_tool_cls(MSCFramework.MSC, ToolType.TRACKER,
tool_style="all")
+for tool in tools.values():
+ msc_utils.register_tool_cls(factory.create(tool))
diff --git a/python/tvm/contrib/msc/framework/tensorrt/tools/__init__.py
b/python/tvm/contrib/msc/framework/tensorrt/tools/__init__.py
index 0247da2642..ecc82bc40f 100644
--- a/python/tvm/contrib/msc/framework/tensorrt/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tensorrt/tools/__init__.py
@@ -17,3 +17,4 @@
"""tvm.contrib.msc.framework.tensorrt.tools"""
from .prune import *
+from .track import *
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/framework/tensorrt/tools/track/__init__.py
similarity index 91%
copy from python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
copy to python/tvm/contrib/msc/framework/tensorrt/tools/track/__init__.py
index 94e19b7e07..88897c1da5 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tensorrt/tools/track/__init__.py
@@ -14,6 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-"""tvm.contrib.msc.framework.tensorflow.tools"""
+"""tvm.contrib.msc.framework.tensorrt.tools.track"""
-from .prune import *
+from .tracker import *
diff --git a/python/tvm/contrib/msc/framework/tensorrt/tools/track/tracker.py
b/python/tvm/contrib/msc/framework/tensorrt/tools/track/tracker.py
new file mode 100644
index 0000000000..10ae794ca0
--- /dev/null
+++ b/python/tvm/contrib/msc/framework/tensorrt/tools/track/tracker.py
@@ -0,0 +1,159 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# pylint: disable=unused-argument
+"""tvm.contrib.msc.framework.tensorrt.tools.track.tracker"""
+
+from typing import Dict, List
+
+from tvm.contrib.msc.core.tools.tool import ToolType, ToolStrategy
+from tvm.contrib.msc.core.tools.track import BaseTracker
+from tvm.contrib.msc.core.utils.namespace import MSCFramework
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class TensorRTTrackerFactory(object):
+ """Tracker factory for tensorrt"""
+
+ def create(self, base_cls: BaseTracker) -> BaseTracker:
+ """Create adaptive tracker
+
+ Parameters
+ ----------
+ base_cls: BaseTracker
+ The base tracker class
+
+ Returns
+ -------
+ tracker_cls: BaseTracker
+ The tracker class.
+ """
+
+ class Tracker(base_cls):
+ """Adaptive tracker for tensorrt"""
+
+ def _execute_before_build(self, codegen_context: dict) -> dict:
+ """Execute before model build
+
+ Parameters
+ ----------
+ codegen_context: dict
+ The context.
+
+ Returns
+ ----------
+ codegen_context: dict
+ The processed context.
+ """
+
+ self._track_tensors = {}
+ super()._execute_before_build(codegen_context)
+
+ def _execute_before_forward(self, step_context: dict) -> dict:
+ """Execute before model forward
+
+ Parameters
+ ----------
+ step_context: dict
+ The context.
+
+ Returns
+ ----------
+ step_context: dict
+ The processed context.
+ """
+
+ for name, data in step_context["datas"].items():
+ if name not in self._track_tensors:
+ continue
+ consumer = self._track_tensors[name]["consumer"]
+ strategys = self._get_tensor_strategys(name, consumer)
+ self._track_tensor(data.asnumpy(), name, consumer,
strategys)
+ return super()._execute_before_forward(step_context)
+
+ def _execute_after_forward(self, step_context: dict) -> dict:
+ """Execute after model forward
+
+ Parameters
+ ----------
+ step_context: dict
+ The context.
+
+ Returns
+ ----------
+ step_context: dict
+ The processed context.
+ """
+
+ for name, data in step_context["datas"].items():
+ if name not in self._track_tensors:
+ continue
+ consumer = self._track_tensors[name]["consumer"]
+ strategys = self._get_tensor_strategys(name, consumer)
+ self._track_tensor(data.asnumpy(), name, consumer,
strategys)
+ return super()._execute_after_forward(step_context)
+
+ def _process_tensor(
+ self,
+ tensor_ctx: Dict[str, str],
+ name: str,
+ consumer: str,
+ scope: str,
+ strategys: List[ToolStrategy],
+ ) -> Dict[str, str]:
+ """Process tensor
+
+ Parameters
+ -------
+ tensor_ctx: dict<str, str>
+ Tensor describe items.
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+ scope: str
+ The scope mark teacher| student| null.
+ strategys: list<ToolStrategy>
+ The strategys for the tensor.
+
+ Returns
+ -------
+ tensor_ctx: dict<str, str>
+ Tensor items with processed.
+ """
+
+ if self.is_weight(name):
+ return self._track_tensor(self.get_data(name), name,
consumer, strategys)
+ if name not in self._track_tensors:
+ self._track_tensors[name] = {
+ "consumer": consumer,
+ }
+ tensor_ctx["processed"].append(
+ "{}->markOutput(*{});".format(tensor_ctx["ctx"],
tensor_ctx["tensor"])
+ )
+ return tensor_ctx
+
+ @classmethod
+ def framework(cls):
+ return MSCFramework.TENSORRT
+
+ return Tracker
+
+
+factory = TensorRTTrackerFactory()
+tools = msc_utils.get_registered_tool_cls(MSCFramework.MSC, ToolType.TRACKER,
tool_style="all")
+for tool in tools.values():
+ msc_utils.register_tool_cls(factory.create(tool))
diff --git a/python/tvm/contrib/msc/framework/torch/frontend/translate.py
b/python/tvm/contrib/msc/framework/torch/frontend/translate.py
index 2dce394708..3ac1b81a2c 100644
--- a/python/tvm/contrib/msc/framework/torch/frontend/translate.py
+++ b/python/tvm/contrib/msc/framework/torch/frontend/translate.py
@@ -57,7 +57,7 @@ def set_weight_alias(graph: MSCGraph) -> MSCGraph:
alias = node.name.replace(".", "_") + ".running_var"
else:
alias = node.name.replace(".", "_") + "." + ref
- weight.set_alias(alias)
+ graph.set_tensor_alias(weight, alias)
return graph
diff --git a/python/tvm/contrib/msc/framework/torch/tools/__init__.py
b/python/tvm/contrib/msc/framework/torch/tools/__init__.py
index ff26491f54..dda1e13822 100644
--- a/python/tvm/contrib/msc/framework/torch/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/torch/tools/__init__.py
@@ -17,3 +17,4 @@
"""tvm.contrib.msc.framework.torch.tools"""
from .prune import *
+from .track import *
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/framework/torch/tools/track/__init__.py
similarity index 91%
copy from python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
copy to python/tvm/contrib/msc/framework/torch/tools/track/__init__.py
index 94e19b7e07..55951fe3a9 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/torch/tools/track/__init__.py
@@ -14,6 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-"""tvm.contrib.msc.framework.tensorflow.tools"""
+"""tvm.contrib.msc.framework.torch.tools.track"""
-from .prune import *
+from .tracker import *
diff --git a/python/tvm/contrib/msc/framework/torch/tools/track/tracker.py
b/python/tvm/contrib/msc/framework/torch/tools/track/tracker.py
new file mode 100644
index 0000000000..0fa065153b
--- /dev/null
+++ b/python/tvm/contrib/msc/framework/torch/tools/track/tracker.py
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""tvm.contrib.msc.framework.torch.tools.track.tracker"""
+
+from tvm.contrib.msc.core.tools.tool import ToolType
+from tvm.contrib.msc.core.tools.track import BaseTracker
+from tvm.contrib.msc.core.utils.namespace import MSCFramework
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class TorchTrackerFactory(object):
+ """Tracker factory for torch"""
+
+ def create(self, base_cls: BaseTracker) -> BaseTracker:
+ """Create adaptive tracker
+
+ Parameters
+ ----------
+ base_cls: BaseTracker
+ The base tracker class
+
+ Returns
+ -------
+ tracker_cls: BaseTracker
+ The tracker class.
+ """
+
+ class Tracker(base_cls):
+ """Adaptive tracker for torch"""
+
+ @classmethod
+ def framework(cls):
+ return MSCFramework.TORCH
+
+ return Tracker
+
+
+factory = TorchTrackerFactory()
+tools = msc_utils.get_registered_tool_cls(MSCFramework.MSC, ToolType.TRACKER,
tool_style="all")
+for tool in tools.values():
+ msc_utils.register_tool_cls(factory.create(tool))
diff --git a/python/tvm/contrib/msc/framework/tvm/tools/__init__.py
b/python/tvm/contrib/msc/framework/tvm/tools/__init__.py
index 91f07fd581..226ae3102d 100644
--- a/python/tvm/contrib/msc/framework/tvm/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tvm/tools/__init__.py
@@ -17,3 +17,4 @@
"""tvm.contrib.msc.framework.tvm.tools"""
from .prune import *
+from .track import *
diff --git a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
b/python/tvm/contrib/msc/framework/tvm/tools/track/__init__.py
similarity index 91%
copy from python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
copy to python/tvm/contrib/msc/framework/tvm/tools/track/__init__.py
index 94e19b7e07..f99f09767d 100644
--- a/python/tvm/contrib/msc/framework/tensorflow/tools/__init__.py
+++ b/python/tvm/contrib/msc/framework/tvm/tools/track/__init__.py
@@ -14,6 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-"""tvm.contrib.msc.framework.tensorflow.tools"""
+"""tvm.contrib.msc.framework.tvm.tools.track"""
-from .prune import *
+from .tracker import *
diff --git a/python/tvm/contrib/msc/framework/tvm/tools/track/tracker.py
b/python/tvm/contrib/msc/framework/tvm/tools/track/tracker.py
new file mode 100644
index 0000000000..cf5ab49e82
--- /dev/null
+++ b/python/tvm/contrib/msc/framework/tvm/tools/track/tracker.py
@@ -0,0 +1,155 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# pylint: disable=unused-argument
+"""tvm.contrib.msc.framework.tvm.tools.track.tracker"""
+
+from typing import List, Union
+
+import tvm
+from tvm.contrib.msc.core.tools.tool import ToolType, ToolStrategy
+from tvm.contrib.msc.core.tools.track import BaseTracker
+from tvm.contrib.msc.core.utils.namespace import MSCFramework
+from tvm.contrib.msc.core import utils as msc_utils
+
+
+class TVMTrackerFactory(object):
+ """Tracker factory for tvm"""
+
+ def create(self, base_cls: BaseTracker) -> BaseTracker:
+ """Create adaptive tracker
+
+ Parameters
+ ----------
+ base_cls: BaseTracker
+ The base tracker class
+
+ Returns
+ -------
+ tracker_cls: BaseTracker
+ The tracker class.
+ """
+
+ class Tracker(base_cls):
+ """Adaptive tracker for tvm"""
+
+ def _execute_before_build(self, block_builder:
tvm.relax.BlockBuilder):
+ """Execute before model build
+
+ Parameters
+ ----------
+ block_builder: tvm.relax.BlockBuilder
+ The block builder.
+ """
+
+ self._block_builder = block_builder
+ self._track_tensors, self._track_names = {}, []
+ super()._execute_before_build(block_builder)
+
+ def _execute_after_build(
+ self, output: Union[tvm.relax.Var, List[tvm.relax.DataflowVar]]
+ ) -> List[tvm.relax.Var]:
+ """Execute after model build
+
+ Parameters
+ ----------
+ output: var or list<var>
+ The output var of the model.
+
+ Returns
+ -------
+ outputs: list<var>
+ The modified outputs var.
+ """
+
+ self._track_names = list(sorted(self._track_tensors.keys()))
+ track_tensors = [self._track_tensors[o]["tensor"] for o in
self._track_names]
+ if isinstance(output, tvm.relax.Var):
+ return super()._execute_after_build([output] +
track_tensors)
+ return super()._execute_after_build(output + track_tensors)
+
+ def _execute_after_forward(
+ self, outputs: List[tvm.runtime.NDArray]
+ ) -> Union[tvm.runtime.NDArray, List[tvm.runtime.NDArray]]:
+ """Execute after model forward
+
+ Parameters
+ ----------
+ outputs: list<np.ndarray>
+ The output datas.
+
+ Returns
+ -------
+ output: np.ndarray or list<np.ndarray>
+ The modified output ndarray.
+ """
+
+ output_num = len(outputs) - len(self._track_names)
+ for data, name in zip(outputs[output_num:], self._track_names):
+ consumer = self._track_tensors[name]["consumer"]
+ strategys = self._get_tensor_strategys(name, consumer)
+ self._track_tensor(data, name, consumer, strategys)
+ if output_num == 1:
+ return super()._execute_after_forward(outputs[0])
+ return super()._execute_after_forward(outputs[:output_num])
+
+ def _process_tensor(
+ self,
+ tensor: tvm.relax.DataflowVar,
+ name: str,
+ consumer: str,
+ scope: str,
+ strategys: List[ToolStrategy],
+ ) -> tvm.relax.DataflowVar:
+ """Process tensor
+
+ Parameters
+ -------
+ tensor: Any
+ Tensor in framework
+ name: str
+ The name of the tensor.
+ consumer: str
+ The name of the consumer.
+ scope: str
+ The scope mark teacher| student| null.
+ strategys: list<ToolStrategy>
+ The strategys for the tensor.
+
+ Returns
+ -------
+ tensor: Any
+ The processed tensor.
+ """
+
+ if self.is_weight(name):
+ return self._track_tensor(self.get_data(name), name,
consumer, strategys)
+ if name not in self._track_tensors:
+ self._track_tensors[name] = {"consumer": consumer,
"tensor": tensor}
+ self._track_names.append(name)
+ return tensor
+
+ @classmethod
+ def framework(cls):
+ return MSCFramework.TVM
+
+ return Tracker
+
+
+factory = TVMTrackerFactory()
+tools = msc_utils.get_registered_tool_cls(MSCFramework.MSC, ToolType.TRACKER,
tool_style="all")
+for tool in tools.values():
+ msc_utils.register_tool_cls(factory.create(tool))
diff --git a/python/tvm/contrib/msc/pipeline/manager.py
b/python/tvm/contrib/msc/pipeline/manager.py
index 4f31eeacfa..bbd6d452ad 100644
--- a/python/tvm/contrib/msc/pipeline/manager.py
+++ b/python/tvm/contrib/msc/pipeline/manager.py
@@ -114,15 +114,6 @@ class BaseManager(object):
config = self._update_runner_config(config, stage)
config = self._update_tool_config(config)
- def _get_tool_stage(tool_type: str) -> str:
- if tool_type == ToolType.PRUNER:
- return MSCStage.PRUNE
- if tool_type == ToolType.QUANTIZER:
- return MSCStage.QUANTIZE
- if tool_type == ToolType.DISTILLER:
- return MSCStage.DISTILL
- return tool_type
-
def _set_debug_level(stage: str, stage_config: dict, default: int =
None) -> dict:
if "debug_level" in stage_config:
debug_levels[stage] = stage_config["debug_level"]
@@ -141,7 +132,7 @@ class BaseManager(object):
if t_type not in config["optimize"]:
continue
debug_levels = _set_debug_level(
- _get_tool_stage(t_type), config["optimize"][t_type],
debug_level
+ self._get_tool_stage(t_type), config["optimize"][t_type],
debug_level
)
ordered_keys = [
"model_type",
@@ -378,16 +369,14 @@ class BaseManager(object):
The runner.
"""
+ runner_cls = self._get_runner_cls(stage_config["run_type"])
+
+ def _tool_enabled(tool_type: str) -> bool:
+ return tool_type in stage_config and
runner_cls.support_tool(tool_type)
+
# run prune
- if ToolType.PRUNER in stage_config:
- self._tools_config[ToolType.PRUNER] = stage_config[ToolType.PRUNER]
- plan_file = stage_config[ToolType.PRUNER]["plan_file"]
- if os.path.isfile(plan_file):
- self._logger.info("Skip %s with plan_file %s",
ToolType.PRUNER, plan_file)
- else:
- msc_utils.time_stamp(MSCStage.PRUNE)
- runner = self._create_tool_runner(MSCStage.PRUNE, stage_config)
- runner.apply_tool(ToolType.PRUNER, self._data_loader)
+ if _tool_enabled(ToolType.PRUNER):
+ self._apply_tool(ToolType.PRUNER, stage_config)
# optimize and get the runner
msc_utils.time_stamp(MSCStage.OPTIMIZE)
@@ -488,7 +477,6 @@ class BaseManager(object):
if self._runner:
self._runner.destory()
- debug_level = self._debug_levels.get(stage, 0)
cache_dir = msc_utils.get_cache_dir().create_dir(stage) if use_cache
else None
tools_config = tools_config or {}
msc_utils.time_stamp(stage + ".build", False)
@@ -496,14 +484,14 @@ class BaseManager(object):
run_config = msc_utils.copy_dict(stage_config.get("run_config"))
if "generate_config" not in run_config:
run_config["generate_config"] = {}
- run_config["generate_config"].update(
- {
- "build_folder": msc_utils.get_build_dir().create_dir(
- stage, cleanup=(debug_level == 0)
- ),
- }
+ cleanup = self._debug_levels.get(stage, 0) == 0
+ run_config["generate_config"]["build_folder"] =
msc_utils.get_build_dir().create_dir(
+ stage, cleanup=cleanup
)
- self._logger.debug("Create runner(%s) by %s(%s)", stage,
runner_cls.__name__, run_config)
+ opt_config = self._config.get("optimize", {})
+ if ToolType.TRACKER in opt_config and
runner_cls.support_tool(ToolType.TRACKER):
+ tools_config = {**tools_config, ToolType.TRACKER:
opt_config[ToolType.TRACKER]}
+ # Build runner
runner = runner_cls(
self._relax_mod,
tools_config=tools_config,
@@ -519,10 +507,12 @@ class BaseManager(object):
self._report["profile"][stage] = self._profile_runner(runner,
stage_config)
if use_cache:
runner.save_cache(cache_dir)
+ if runner.get_tool(ToolType.TRACKER):
+ runner.apply_tool(ToolType.TRACKER)
return runner
- def _create_tool_runner(self, tool_type: str, stage_config: dict) ->
BaseRunner:
- """Create runner with tool.
+ def _apply_tool(self, tool_type: str, stage_config: dict, add_tool: bool =
True) -> str:
+ """Apply tool with runner
Parameters
----------
@@ -530,24 +520,41 @@ class BaseManager(object):
The tool type.
stage_config: dict
The config of this stage.
+ add_tool: bool
+ Whether to add tool in self._tools.
Returns
-------
- runner: BaseRunner
- The runner.
+ plan_file: str
+ The plan_file path.
"""
+ assert tool_type in stage_config, "Can not find config for tool " +
str(tool_type)
+ tool_stage, tool_config = self._get_tool_stage(tool_type),
stage_config[tool_type]
+ plan_file = tool_config["plan_file"]
+ if "gym_configs" in tool_config:
+ gym_configs = tool_config.pop("gym_configs")
+ else:
+ gym_configs = None
+ if add_tool:
+ self._tools_config[tool_type] = tool_config
+ tools_config = self._tools_config
+ else:
+ tools_config = {**self._tools_config, tool_type: tool_config}
+ if os.path.isfile(plan_file):
+ self._logger.info("Skip %s with plan %s", tool_type, plan_file)
+ return plan_file
+ msc_utils.time_stamp(tool_stage)
t_stage_config = {
"run_type": stage_config["run_type"],
"run_config": stage_config["run_config"],
}
- return self._create_runner(
- tool_type,
- t_stage_config,
- tools_config=self._tools_config,
- profile=False,
- use_cache=False,
+ runner = self._create_runner(
+ tool_stage, t_stage_config, tools_config=tools_config,
profile=False, use_cache=False
)
+ if gym_configs:
+ raise NotImplementedError("Gym is not implemented")
+ return runner.apply_tool(tool_type, self._data_loader)
def _profile_runner(self, runner: BaseRunner, stage_config: str) -> dict:
"""Profile the runner.
@@ -590,7 +597,7 @@ class BaseManager(object):
pass_rate = float(passed) / total
report["accuracy"] = "{}/{}({:.2f}%)".format(passed, total,
pass_rate * 100)
title = "Check({}) pass {}".format(stage, report["accuracy"])
- self._logger.debug(msc_utils.msg_block(title, acc_report))
+ self._logger.debug(msc_utils.msg_block(title, acc_report, width=0))
msg += " acc {} iters -> {}".format(len(loader),
report["accuracy"])
if runner.get_tool(ToolType.PRUNER) or
runner.get_tool(ToolType.QUANTIZER):
self._logger.debug("Disable accuracy check(%s) by tools",
stage)
@@ -603,7 +610,12 @@ class BaseManager(object):
)
)
- benchmark_config = profile_config.get("benchmark", {})
+ # benchmark model
+ if runner.get_tool(ToolType.TRACKER):
+ benchmark_config = None
+ self._logger.debug("Disable benchmark(%s) by tools", stage)
+ else:
+ benchmark_config = profile_config.get("benchmark", {})
if benchmark_config:
for _ in range(benchmark_config.get("warm_up", 10)):
runner.run(self._sample_inputs)
@@ -764,6 +776,28 @@ class BaseManager(object):
)
return config
+ def _get_tool_stage(self, tool_type: str) -> str:
+ """Map the stage according to tool_type
+
+ Parameters
+ ----------
+ tool_type: str
+ The tool type.
+
+ Returns
+ -------
+ stage: str
+ The stage.
+ """
+
+ if tool_type == ToolType.PRUNER:
+ return MSCStage.PRUNE
+ if tool_type == ToolType.QUANTIZER:
+ return MSCStage.QUANTIZE
+ if tool_type == ToolType.DISTILLER:
+ return MSCStage.DISTILL
+ return tool_type
+
def get_runnable(self, ret_type: str = "runner") -> Any:
"""Return object by type.
diff --git a/src/contrib/msc/core/ir/graph.cc b/src/contrib/msc/core/ir/graph.cc
index c563ccb410..2cdb326e77 100644
--- a/src/contrib/msc/core/ir/graph.cc
+++ b/src/contrib/msc/core/ir/graph.cc
@@ -1263,6 +1263,18 @@ TVM_REGISTER_GLOBAL("msc.core.MSCTensor")
return MSCTensor(name, dtype, layout, shape, alias);
});
+TVM_REGISTER_GLOBAL("msc.core.MSCTensorToJson")
+ .set_body_typed([](const MSCTensor& tensor) -> String {
+ const auto& tensor_json = tensor->ToJson();
+ std::ostringstream os;
+ dmlc::JSONWriter writer(&os);
+ tensor_json.Save(&writer);
+ return os.str();
+ });
+
+TVM_REGISTER_GLOBAL("msc.core.MSCTensorFromJson")
+ .set_body_typed([](const String& tensor_json) -> MSCTensor { return
MSCTensor(tensor_json); });
+
TVM_REGISTER_GLOBAL("msc.core.MSCJoint")
.set_body_typed([](Integer index, const String& name, const String&
shared_ref,
const String& optype, const Map<String, String>& attrs,
@@ -1293,6 +1305,11 @@ TVM_REGISTER_GLOBAL("msc.core.WeightJoint")
b_friends);
});
+TVM_REGISTER_GLOBAL("msc.core.WeightJointSetAttr")
+ .set_body_typed([](const WeightJoint& node, const String& key, const
String& value) {
+ node->attrs.Set(key, value);
+ });
+
TVM_REGISTER_GLOBAL("msc.core.MSCGraph")
.set_body_typed([](const String& name, const Array<MSCJoint>& nodes,
const Array<String>& input_names,
diff --git a/src/contrib/msc/core/ir/graph.h b/src/contrib/msc/core/ir/graph.h
index 67855deb97..fbcdeb4d0c 100644
--- a/src/contrib/msc/core/ir/graph.h
+++ b/src/contrib/msc/core/ir/graph.h
@@ -385,7 +385,7 @@ class BaseJointNode : public Object {
/*! \brief The shared_ref of node, can be changed. */
String shared_ref;
/*! \brief The attributes of node. */
- Map<String, String> attrs;
+ mutable Map<String, String> attrs;
/*! \brief The parents of node. */
Array<ObjectRef> parents;
/*! \brief The children of node. */
diff --git a/src/contrib/msc/framework/tensorrt/codegen.cc
b/src/contrib/msc/framework/tensorrt/codegen.cc
index 6efc9b26af..4cba1bdce3 100644
--- a/src/contrib/msc/framework/tensorrt/codegen.cc
+++ b/src/contrib/msc/framework/tensorrt/codegen.cc
@@ -94,7 +94,6 @@ void TensorRTCodeGen::CodeGenClassDefine() {
.func_call("malloc", "cpu_buffers[" + idx_var + "]")
.call_arg(GetTensorBytes(tensor));
};
-
stack_.line("#include \"" + graph()->name + ".h\"").line();
StartNamespace();
// start define build method
@@ -105,6 +104,12 @@ void TensorRTCodeGen::CodeGenClassDefine() {
stack_.func_arg("config", "TRTPtr<IBuilderConfig>&");
}
stack_.func_arg("logger", "TRTLogger&").func_start();
+ // save codegen before build
+ if (config()->use_tools) {
+ const auto* pf = runtime::Registry::Get("msc_tool.codegen_step");
+ ICHECK(pf != nullptr) << "Cannot find msc_tool.codegen_step func.";
+ before_build_codes_ = (*pf)(GetStepCtx(), "before_build", graph()->name,
config()->tools_tag);
+ }
if (graph()->weight_holders.size() > 0) {
stack_.assign("mWeights", "TRTUtils::LoadWeights(\"" + graph()->name +
".wts\")");
}
@@ -184,6 +189,12 @@ void TensorRTCodeGen::CodeGenClassDefine() {
.call_arg(DocUtils::ToStrDoc("use int8 to build the engine"))
.cond_end();
}
+ // save codegen after build
+ if (config()->use_tools) {
+ const auto* pf = runtime::Registry::Get("msc_tool.codegen_step");
+ ICHECK(pf != nullptr) << "Cannot find msc_tool.codegen_step func.";
+ after_build_codes_ = (*pf)(GetStepCtx(), "after_build", graph()->name,
config()->tools_tag);
+ }
// end define build method
stack_.func_end("true");
// start define test function
@@ -339,15 +350,9 @@ void TensorRTCodeGen::CodeGenMain() {
.func_call("createBuilderConfig", NullOpt, DocUtils::ToPtrDoc("builder"))
.pop_nest();
ReturnOnFail("config", "Failed to create config");
- // codegen before build
- if (config()->use_tools) {
- const auto* pf = runtime::Registry::Get("msc_tool.codegen_step");
- ICHECK(pf != nullptr) << "Cannot find msc_tool.codegen_step func.";
- const Array<String>& lines =
- (*pf)(GetStepCtx(), "before_build", graph()->name,
config()->tools_tag);
- for (const auto& l : lines) {
- stack_.line(l);
- }
+ // add codegen before build
+ for (const auto& l : before_build_codes_) {
+ stack_.line(l);
}
// build model
stack_.comment("Build model")
@@ -360,15 +365,9 @@ void TensorRTCodeGen::CodeGenMain() {
}
stack_.call_arg("logger");
ReturnOnFail("pass", "Failed to build model");
- // codegen after build
- if (config()->use_tools) {
- const auto* pf = runtime::Registry::Get("msc_tool.codegen_step");
- ICHECK(pf != nullptr) << "Cannot find msc_tool.codegen_step func.";
- const Array<String>& lines =
- (*pf)(GetStepCtx(), "after_build", graph()->name, config()->tools_tag);
- for (const auto& l : lines) {
- stack_.line(l);
- }
+ // add codegen after build
+ for (const auto& l : after_build_codes_) {
+ stack_.line(l);
}
// Set profile flag
stack_.comment("Set profile flag")
diff --git a/src/contrib/msc/framework/tensorrt/codegen.h
b/src/contrib/msc/framework/tensorrt/codegen.h
index 21b556d1ce..ea06a17f7c 100644
--- a/src/contrib/msc/framework/tensorrt/codegen.h
+++ b/src/contrib/msc/framework/tensorrt/codegen.h
@@ -84,6 +84,10 @@ class TensorRTCodeGen : public
CppCodeGen<TensorRTCodeGenConfig, TensorRTCodeGen
template <typename T>
const String ToDims(const std::vector<T>& dims, bool use_ndim = true);
const String ToDims(const Array<Integer>& dims, bool use_ndim = true);
+
+ private:
+ Array<String> before_build_codes_;
+ Array<String> after_build_codes_;
};
} // namespace msc
diff --git a/tests/python/contrib/test_msc/test_tools.py
b/tests/python/contrib/test_msc/test_tools.py
index 037507cf69..f396b81ea4 100644
--- a/tests/python/contrib/test_msc/test_tools.py
+++ b/tests/python/contrib/test_msc/test_tools.py
@@ -69,12 +69,30 @@ def _get_config(
def get_tool_config(tool_type):
+ """Get config for the tool"""
config = {}
if tool_type == ToolType.PRUNER:
config = {
"plan_file": "msc_pruner.json",
"strategys": [{"method": "per_channel", "density": 0.8}],
}
+ elif tool_type == ToolType.QUANTIZER:
+ raise NotImplementedError("Quantizer is not supported")
+ elif tool_type == ToolType.TRACKER:
+ config = {
+ "plan_file": "msc_tracker.json",
+ "strategys": [
+ {
+ "method": "save_compared",
+ "compare_to": {
+ "optimize": ["baseline"],
+ "compile": ["optimize", "baseline"],
+ },
+ "op_types": ["nn.relu"],
+ "tensor_types": ["output"],
+ }
+ ],
+ }
return {tool_type: config}
@@ -132,57 +150,67 @@ def _test_from_torch(
manager.destory()
[email protected]("tool_type", [ToolType.PRUNER])
-def test_tvm_tools(tool_type):
+def get_model_info(compile_type):
+ """Get the model info"""
+ if compile_type == MSCFramework.TVM:
+ return {
+ "inputs": [
+ {"name": "input_0", "shape": [1, 3, 224, 224], "dtype":
"float32", "layout": "NCHW"}
+ ],
+ "outputs": [{"name": "output", "shape": [1, 1000], "dtype":
"float32", "layout": "NC"}],
+ "nodes": {
+ "total": 229,
+ "input": 1,
+ "nn.conv2d": 53,
+ "nn.batch_norm": 53,
+ "get_item": 53,
+ "nn.relu": 49,
+ "nn.max_pool2d": 1,
+ "add": 16,
+ "nn.adaptive_avg_pool2d": 1,
+ "reshape": 1,
+ "msc.linear_bias": 1,
+ },
+ }
+ if compile_type == MSCFramework.TENSORRT:
+ return {
+ "inputs": [
+ {"name": "input_0", "shape": [1, 3, 224, 224], "dtype":
"float32", "layout": "NCHW"}
+ ],
+ "outputs": [{"name": "output", "shape": [1, 1000], "dtype":
"float32", "layout": ""}],
+ "nodes": {"total": 2, "input": 1, "msc_tensorrt": 1},
+ }
+ raise TypeError("Unexpected compile_type " + str(compile_type))
+
+
[email protected]("tool_type", [ToolType.PRUNER, ToolType.TRACKER])
+def test_tvm_tool(tool_type):
"""Test tools for tvm"""
- model_info = {
- "inputs": [
- {"name": "input_0", "shape": [1, 3, 224, 224], "dtype": "float32",
"layout": "NCHW"}
- ],
- "outputs": [{"name": "output", "shape": [1, 1000], "dtype": "float32",
"layout": "NC"}],
- "nodes": {
- "total": 229,
- "input": 1,
- "nn.conv2d": 53,
- "nn.batch_norm": 53,
- "get_item": 53,
- "nn.relu": 49,
- "nn.max_pool2d": 1,
- "add": 16,
- "nn.adaptive_avg_pool2d": 1,
- "reshape": 1,
- "msc.linear_bias": 1,
- },
- }
tool_config = get_tool_config(tool_type)
- _test_from_torch(MSCFramework.TVM, tool_config, model_info,
is_training=True)
+ _test_from_torch(
+ MSCFramework.TVM, tool_config, get_model_info(MSCFramework.TVM),
is_training=True
+ )
@requires_tensorrt
[email protected](
- "tool_type,use_native",
- [(ToolType.PRUNER, False)],
-)
-def test_tensorrt_tools(tool_type, use_native):
[email protected]("tool_type", [ToolType.PRUNER, ToolType.TRACKER])
+def test_tensorrt_tool(tool_type):
"""Test tools for tensorrt"""
- model_info = {
- "inputs": [
- {"name": "input_0", "shape": [1, 3, 224, 224], "dtype": "float32",
"layout": "NCHW"}
- ],
- "outputs": [{"name": "output", "shape": [1, 1000], "dtype": "float32",
"layout": ""}],
- "nodes": {"total": 2, "input": 1, "msc_tensorrt": 1},
- }
tool_config = get_tool_config(tool_type)
- if tool_type == ToolType.QUANTIZER and use_native:
+ if tool_type == ToolType.QUANTIZER:
tool_config[ToolType.QUANTIZER]["strategys"] = []
- optimize_type = MSCFramework.TENSORRT if use_native else None
+ optimize_type = MSCFramework.TENSORRT
+ else:
+ optimize_type = None
_test_from_torch(
MSCFramework.TENSORRT,
tool_config,
- model_info,
+ get_model_info(MSCFramework.TENSORRT),
is_training=False,
+ atol=5e-2,
+ rtol=5e-2,
optimize_type=optimize_type,
)