diff --git a/.cmake-format.py b/.cmake-format.py index 36193e4..2560562 100644 --- a/.cmake-format.py +++ b/.cmake-format.py @@ -1,8 +1,6 @@ # ------------------------------------------------ # Options affecting comment reflow and formatting. # ------------------------------------------------ -from __future__ import annotations - with section("markup"): # enable comment markup parsing and reflow enable_markup = False diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2bdb582..5bed6db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,12 +10,8 @@ repos: - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - - repo: https://github.com/psf/black - rev: 23.1.0 + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 23.9.1 hooks: - id: black - repo: https://github.com/PyCQA/autoflake @@ -31,10 +27,10 @@ repos: # - "--remove-unused-variables" - "--remove-all-unused-imports" - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.254 + rev: v0.0.292 hooks: - - id: ruff - args: [--fix, --exit-non-zero-on-fix, --no-cache] + - id: ruff + args: [--fix, --exit-non-zero-on-fix, --no-cache] - repo: https://github.com/asottile/yesqa rev: v1.4.0 hooks: diff --git a/examples/native_interpreter/pyproject.toml b/examples/native_interpreter/pyproject.toml new file mode 100644 index 0000000..74edba7 --- /dev/null +++ b/examples/native_interpreter/pyproject.toml @@ -0,0 +1,3 @@ +[tool.ruff.isort] +lines-between-types = 1 +known-first-party = ["build"] diff --git a/examples/native_interpreter/use_interpreter.py b/examples/native_interpreter/use_interpreter.py index c109992..2898ff7 100644 --- a/examples/native_interpreter/use_interpreter.py +++ b/examples/native_interpreter/use_interpreter.py @@ -2,10 +2,9 @@ import paddle -from build import myinterpreter - import paddlefx +from build import myinterpreter from paddlefx import symbolic_trace @@ -22,8 +21,8 @@ def net(a, b): traced_layer.graph.print_tabular() # the very simple IR we want to lower fx graph to -# each instruction is a list of string of: operation, left_operand, right_operand, result -# only two op supported: add, mul +# each instruction is a list of string of: operation, left_operand, +# right_operand, result only two op supported: add, mul input_names = [] instructions = [] diff --git a/examples/resnet_dynamo.py b/examples/resnet_dynamo.py index 6a9b256..66bacfc 100644 --- a/examples/resnet_dynamo.py +++ b/examples/resnet_dynamo.py @@ -12,7 +12,7 @@ from paddlefx.compiler.tvm import TVMCompiler paddle.seed(1234) -# logging.getLogger().setLevel(logging.DEBUG) + compiler = TVMCompiler( full_graph=True, diff --git a/examples/simple_compiler.py b/examples/simple_compiler.py index e5a3559..a9a837e 100644 --- a/examples/simple_compiler.py +++ b/examples/simple_compiler.py @@ -11,8 +11,6 @@ paddle.seed(1234) -# logging.getLogger().setLevel(logging.DEBUG) - def inner_func(x, y): p = paddle.add(x, y) diff --git a/examples/simple_dynamo.py b/examples/simple_dynamo.py index ceb9c76..321912f 100644 --- a/examples/simple_dynamo.py +++ b/examples/simple_dynamo.py @@ -1,7 +1,5 @@ from __future__ import annotations -import logging - import numpy as np import paddle import paddle.nn @@ -10,7 +8,6 @@ from paddlefx.compiler import DummyCompiler, TVMCompiler -logging.getLogger().setLevel(logging.DEBUG) static_compier = DummyCompiler(full_graph=True, print_tabular_mode="rich") compiler = TVMCompiler(full_graph=True, print_tabular_mode="rich") diff --git a/examples/targets/target_0_add.py b/examples/targets/target_0_add.py index 28544d1..2246241 100644 --- a/examples/targets/target_0_add.py +++ b/examples/targets/target_0_add.py @@ -11,8 +11,6 @@ import paddlefx -logging.basicConfig(level=logging.DEBUG, format="%(message)s") - def my_compiler(gl: paddlefx.GraphLayer, example_inputs: list[paddle.Tensor] = None): print("my_compiler() called with FX graph:") diff --git a/examples/targets/target_1_print.py b/examples/targets/target_1_print.py index 952fa04..71283e2 100644 --- a/examples/targets/target_1_print.py +++ b/examples/targets/target_1_print.py @@ -11,8 +11,6 @@ import paddlefx -logging.basicConfig(level=logging.DEBUG, format="%(message)s") - # TODO: support grpah break for `print` diff --git a/examples/targets/target_2_func.py b/examples/targets/target_2_func.py index 5aa0b43..50e4662 100644 --- a/examples/targets/target_2_func.py +++ b/examples/targets/target_2_func.py @@ -1,20 +1,11 @@ from __future__ import annotations -import logging - -# ignore DeprecationWarning from `pkg_resources` -logging.captureWarnings(True) - - import paddle import paddle.nn import paddlefx import paddlefx.utils -# logging.basicConfig(level=logging.DEBUG, format="%(message)s") -logging.basicConfig(level=logging.INFO, format="%(message)s") - def my_compiler(gl: paddlefx.GraphLayer, example_inputs: list[paddle.Tensor] = None): print("my_compiler() called with FX graph:") diff --git a/examples/targets/target_3_add_paddle.py b/examples/targets/target_3_add_paddle.py index eb7afb8..2b35f61 100644 --- a/examples/targets/target_3_add_paddle.py +++ b/examples/targets/target_3_add_paddle.py @@ -1,10 +1,5 @@ from __future__ import annotations -import logging - -# ignore DeprecationWarning from `pkg_resources` -logging.captureWarnings(True) - import paddle import paddle._C_ops @@ -12,11 +7,6 @@ from paddlefx.compiler import TVMCompiler -logging.basicConfig(level=logging.DEBUG, format="%(message)s") -# logging.basicConfig(level=logging.INFO, format="%(message)s") - -paddle.seed(1234) - def func(x, y): z = paddle.add(x, y) diff --git a/pyproject.toml b/pyproject.toml index 9e9f7e9..02ca062 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,19 +14,25 @@ skip-string-normalization = true # default value may too big to run workers = 4 -# https://pycqa.github.io/isort/docs/configuration/options.html -[tool.isort] -profile = "black" -lines_between_types = 1 -known_first_party = ["paddlefx"] -add_imports = ["from __future__ import annotations"] - # https://beta.ruff.rs/docs/configuration/ [tool.ruff] -select = ["UP"] -ignore = ["UP015"] +exclude = [".cmake-format.py"] +select = [ + "UP", + "F", + "I" +] +ignore = [ + "UP015", + "F405" +] target-version = "py38" +[tool.ruff.isort] +lines-between-types = 1 +known-first-party = ["paddlefx"] +required-imports = ["from __future__ import annotations"] + [tool.pytest.ini_options] minversion = "7.0.0" pythonpath = "tests" diff --git a/requirements.txt b/requirements.txt index cbe2956..fb1d464 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ paddlepaddle>=2.4.0 pydot +loguru +appdirs diff --git a/src/paddlefx/cache_manager.py b/src/paddlefx/cache_manager.py index 3b7818b..4cc56ab 100644 --- a/src/paddlefx/cache_manager.py +++ b/src/paddlefx/cache_manager.py @@ -5,6 +5,8 @@ from typing import TYPE_CHECKING, Callable +from loguru import logger + if TYPE_CHECKING: GuardFunction = Callable[[types.FrameType], bool] GuardedCodes = list["GuardedCode"] @@ -28,7 +30,7 @@ def add_cache(cls, code: types.CodeType, guarded_code: GuardedCode): def get_cache(cls, frame: types.FrameType) -> GuardedCode | None: code: types.CodeType = frame.f_code if code not in cls.cache_dict: - print(f"Firstly call {code}\n") + logger.success(f"Firstly call {code}\n") return None return cls.lookup(frame, cls.cache_dict[code]) @@ -44,17 +46,17 @@ def lookup( try: guard_fn = guarded_code.guard_fn if guard_fn(frame): - print( + logger.success( f"[Cache]: Cache hit, GuardFunction is {guard_fn}\n", ) return guarded_code else: - print( + logger.info( f"[Cache]: Cache miss, GuardFunction is {guard_fn}\n", ) except Exception as e: - print(f"[Cache]: GuardFunction function error: {e}\n") + logger.exception(f"[Cache]: GuardFunction function error: {e}\n") continue - print("[Cache]: all guards missed\n") + logger.success("[Cache]: all guards missed\n") return None diff --git a/src/paddlefx/compiler/tvm.py b/src/paddlefx/compiler/tvm.py index 9e8c685..67f7ee4 100644 --- a/src/paddlefx/compiler/tvm.py +++ b/src/paddlefx/compiler/tvm.py @@ -6,6 +6,8 @@ import paddle.device import tvm +from appdirs import user_cache_dir +from loguru import logger from tvm import auto_scheduler, relay import paddlefx @@ -36,6 +38,8 @@ def __init__( self.tune_mode = tune_mode def compile(self, gl: paddlefx.GraphLayer, example_inputs: list) -> Callable: + cache_path = user_cache_dir('paddlefx') + shape_dict = {} for node in gl.graph.nodes: if node.op == "placeholder": @@ -43,7 +47,7 @@ def compile(self, gl: paddlefx.GraphLayer, example_inputs: list) -> Callable: self.input_index += 1 static_func = paddle.jit.to_static(gl.forward) static_func(*example_inputs) - model_path = f"~/.cache/paddlefx/model_{id(gl)}" + model_path = f"{cache_path}/paddle_static_model/{id(gl)}" paddle.jit.save(static_func, model_path) translated_layer = paddle.jit.load(model_path) mod, params = relay.frontend.from_paddle(translated_layer) @@ -53,21 +57,21 @@ def compile(self, gl: paddlefx.GraphLayer, example_inputs: list) -> Callable: ) for idx, task in enumerate(tasks): - print( - "========== Task %d (workload key: %s) ==========" - % (idx, task.workload_key) + logger.info( + f"========== Task {idx} (workload key: {task.workload_key}) ==========" ) - print(task.compute_dag) + logger.info(task.compute_dag) tuner = auto_scheduler.TaskScheduler(tasks, task_weights) + log_file_path = f"{cache_path}/paddle_static_model/{id(gl)}" tune_option = auto_scheduler.TuningOptions( num_measure_trials=200, early_stopping=10, - measure_callbacks=[auto_scheduler.RecordToFile("log_file")], + measure_callbacks=[auto_scheduler.RecordToFile(log_file_path)], ) tuner.tune(tune_option) - with auto_scheduler.ApplyHistoryBest("log_file"): + with auto_scheduler.ApplyHistoryBest(log_file_path): with tvm.transform.PassContext( opt_level=3, config={"relay.backend.use_auto_scheduler": True} ): diff --git a/src/paddlefx/convert_frame.py b/src/paddlefx/convert_frame.py index ef3039f..c11c2e9 100644 --- a/src/paddlefx/convert_frame.py +++ b/src/paddlefx/convert_frame.py @@ -1,10 +1,11 @@ from __future__ import annotations -import logging import types from typing import TYPE_CHECKING, Callable +from loguru import logger + from .bytecode_transformation import Instruction, transform_code_object from .cache_manager import CodeCacheManager, GuardedCode from .paddle_utils import Tensor, skip_paddle_filename, skip_paddle_frame @@ -31,7 +32,7 @@ def skip_frame(frame: types.FrameType) -> bool: def convert_frame(frame: types.FrameType, compiler_fn: Callable) -> GuardedCode | None: if skip_frame(frame): - logging.debug(f"skip_frame: {frame}") + logger.debug(f"skip_frame: {frame}") return None # TODO: guard_fn is not declared in this scope guard_fn = None @@ -45,12 +46,12 @@ def transform(instructions: list[Instruction], code_options: dict): code_options.update(tracer.output.code_options) instructions[:] = tracer.output.instructions - logging.info(f"convert_frame: {frame}") + logger.info(f"convert_frame: {frame}") code = frame.f_code log_code(code, "ORIGINAL_BYTECODE") if (cached_code := CodeCacheManager.get_cache(frame)) is not None: - logging.info(f"cached_code: {cached_code}") + logger.info(f"cached_code: {cached_code}") return cached_code # TODO: rm torch code dependency diff --git a/src/paddlefx/eval_frame.py b/src/paddlefx/eval_frame.py index bb7d5ce..480a027 100644 --- a/src/paddlefx/eval_frame.py +++ b/src/paddlefx/eval_frame.py @@ -1,11 +1,12 @@ from __future__ import annotations import functools -import logging import types from typing import Callable +from loguru import logger + from ._eval_frame import set_eval_frame from .compiler import DummyCompiler from .convert_frame import convert_frame @@ -54,7 +55,7 @@ def __fn(frame: types.FrameType): guarded_code = convert_frame(frame, backend) return guarded_code except NotImplementedError as e: - logging.debug(f"!! NotImplementedError: {e}") + logger.debug(f"!! NotImplementedError: {e}") except Exception: raise return None diff --git a/src/paddlefx/legacy_module/translator.py b/src/paddlefx/legacy_module/translator.py index 432b227..e8cc805 100644 --- a/src/paddlefx/legacy_module/translator.py +++ b/src/paddlefx/legacy_module/translator.py @@ -1,6 +1,5 @@ from __future__ import annotations -import logging import operator import types @@ -9,6 +8,8 @@ import paddle import paddle.nn +from loguru import logger + from ..bytecode_transformation import Instruction, create_instruction from ..output_graph import OutputGraph from ..proxy import Attribute, Proxy @@ -127,7 +128,7 @@ def call_function(self, fn, args, kwargs): res = self.output.create_node('call_function', fn, args, kwargs) self.stack.push(res) elif is_custom_call: - raise NotImplementedError(f"custom_call is not supported") + raise NotImplementedError("custom_call is not supported") else: raise NotImplementedError(f"call function {fn} is not supported") @@ -236,7 +237,7 @@ def STORE_SUBSCR(self, inst): self.output.create_node('call_method', "__setitem__", [root, idx, value], {}) def POP_TOP(self, inst: Instruction): - value = self.stack.pop() + self.stack.pop() def STORE_FAST(self, inst: Instruction): self.f_locals[inst.argval] = self.stack.pop() @@ -323,7 +324,7 @@ def step(self, inst: Instruction): if not hasattr(self, inst.opname): raise NotImplementedError(f"missing: {inst.opname}") - logging.debug(f"TRACE {inst.opname} {inst.argval} {self.stack}") + logger.debug(f"TRACE {inst.opname} {inst.argval} {self.stack}") getattr(self, inst.opname)(inst) def run(self): diff --git a/src/paddlefx/output_graph.py b/src/paddlefx/output_graph.py index 084fffb..911a7d8 100644 --- a/src/paddlefx/output_graph.py +++ b/src/paddlefx/output_graph.py @@ -1,13 +1,14 @@ from __future__ import annotations import itertools -import logging import types from typing import TYPE_CHECKING, Callable, OrderedDict import paddle +from loguru import logger + from .bytecode_transformation import Instruction, create_instruction from .codegen import PyCodegen from .graph import Graph @@ -109,7 +110,7 @@ def apply_compiler(self, tx: PyEvalBase, rv: list[VariableBase], root): log_code( compiled_fn.__code__, f"COMPILED_FN {compiled_fn_name}", - log_fn=logging.debug, + log_fn=logger.debug, ) compiled_fn = disable(compiled_fn) tx.f_globals[compiled_fn_name] = compiled_fn @@ -120,7 +121,7 @@ def apply_compiler(self, tx: PyEvalBase, rv: list[VariableBase], root): return cg.instructions def compile_subgraph(self, tx: PyEvalBase): - logging.debug( + logger.debug( f"start compile_subgraph, current_instruction: \n{format_instruction(tx.current_instruction)}" # type: ignore ) tx.prune_dead_locals() @@ -164,4 +165,4 @@ def compile_subgraph(self, tx: PyEvalBase): self.add_output_instructions( [PyCodegen(tx).create_store(var) for var in reversed(restore_vars)] ) - log_instructions(self.instructions, 'COMPILE_SUBGRAPH', log_fn=logging.debug) + log_instructions(self.instructions, 'COMPILE_SUBGRAPH', log_fn=logger.debug) diff --git a/src/paddlefx/pyeval.py b/src/paddlefx/pyeval.py index a173923..0933cb1 100644 --- a/src/paddlefx/pyeval.py +++ b/src/paddlefx/pyeval.py @@ -4,13 +4,14 @@ import dis import functools import inspect -import logging import operator import types from collections import OrderedDict from typing import TYPE_CHECKING, Any, Callable, NamedTuple +from loguru import logger + from .bytecode_analysis import livevars_analysis from .bytecode_transformation import ( Instruction, @@ -61,10 +62,10 @@ def wrapper(self: PyEval, inst: Instruction): state = self.get_state() try: return inner_fn(self, inst) - except (BreakGraphError, NotImplementedError) as e: + except (BreakGraphError, NotImplementedError): # TODO: remove NotImplementedError - logging.debug( - f"break_graph_if_unsupported triggered compile", exc_info=True + logger.debug( + "break_graph_if_unsupported triggered compile", exc_info=True ) if not isinstance(self, PyEval): @@ -177,12 +178,12 @@ def step(self): self.next_instruction = None if inst.starts_line and self.lineno != inst.starts_line: self.lineno = inst.starts_line - logging.debug(f"TRACE starts_line {self.f_code.co_filename}:{self.lineno}") + logger.debug(f"TRACE starts_line {self.f_code.co_filename}:{self.lineno}") if len(self.stack) == 0 and isinstance(self, PyEval): self.checkpoint = inst, self.get_state() - logging.debug(f"TRACE {inst.opname} {inst.argval} {self.stack}") + logger.debug(f"TRACE {inst.opname} {inst.argval} {self.stack}") try: if not hasattr(self, inst.opname): @@ -194,12 +195,12 @@ def step(self): except NotImplementedError as e: if self.checkpoint is None: raise - logging.debug(f"!! NotImplementedError: {e}") + logger.debug(f"!! NotImplementedError: {e}") except Exception as e: raise e # fallback - logging.debug(f"graph break from instruction: \n{format_instruction(inst)}") + logger.debug(f"graph break from instruction: \n{format_instruction(inst)}") assert not self.output.instructions assert self.checkpoint is not None continue_inst, state = self.checkpoint @@ -596,8 +597,8 @@ def inline_call( if code.co_name in ("__setitem__", "__setattr__"): raise NotImplementedError(f"inline_call {code.co_name}") - logging.debug(f"INLINING {code}") - log_code(code, "INLINE_BYTECODE", log_fn=logging.debug) + logger.debug(f"INLINING {code}") + log_code(code, "INLINE_BYTECODE", log_fn=logger.debug) bound = inspect.signature(func.var).bind(*args, **kwargs) bound.apply_defaults() @@ -614,7 +615,7 @@ def inline_call( try: tracer.run() except Exception: - logging.debug(f"FAILED INLINING {code}") + logger.debug(f"FAILED INLINING {code}") raise assert tracer.symbolic_result is not None @@ -622,7 +623,7 @@ def inline_call( # Merge symbolic_globals back if parent and child are in the same namespace parent.symbolic_globals.update(tracer.symbolic_globals) - logging.debug(f"DONE INLINING {code}") + logger.debug(f"DONE INLINING {code}") return tracer.symbolic_result def RETURN_VALUE(self, inst: Instruction): @@ -736,7 +737,7 @@ def update(instructions: list[Instruction], code_options: dict): instructions[:] = prefix + instructions new_code = transform_code_object(self.f_code, update) - log_code(new_code, f"RESUME_AT {name}", log_fn=logging.debug) + log_code(new_code, f"RESUME_AT {name}", log_fn=logger.debug) self.f_globals[name] = types.FunctionType(new_code, self.f_globals, name) diff --git a/src/paddlefx/utils.py b/src/paddlefx/utils.py index 3414315..1562023 100644 --- a/src/paddlefx/utils.py +++ b/src/paddlefx/utils.py @@ -1,25 +1,31 @@ from __future__ import annotations import dis -import logging +import os +import sys import traceback import types from typing import TYPE_CHECKING +from loguru import logger + if TYPE_CHECKING: from .bytecode_transformation import Instruction +logger.remove() +logger.add(sys.stdout, level=os.environ.get("LOG_LEVEL", "INFO")) + def format_bytecode(prefix, name, filename, line_no, code): return f"{prefix} {name} {filename} line {line_no} \n{dis.Bytecode(code).dis()}" -def log_bytecode(prefix, name, filename, line_no, code, log_fn=logging.info): +def log_bytecode(prefix, name, filename, line_no, code, log_fn=logger.info): log_fn(format_bytecode(prefix, name, filename, line_no, code)) -def log_code(code: types.CodeType, prefix='', log_fn=logging.info): +def log_code(code: types.CodeType, prefix='', log_fn=logger.info): log_bytecode( prefix, code.co_name, code.co_filename, code.co_firstlineno, code, log_fn=log_fn ) @@ -38,7 +44,7 @@ def format_instruction(inst: dis.Instruction | Instruction): def log_instructions( instructions: list[dis.Instruction] | list[Instruction], prefix='', - log_fn=logging.info, + log_fn=logger.info, ): log_fn(f"{prefix}") for inst in instructions: @@ -53,7 +59,7 @@ def hashable(obj) -> bool: try: hash(obj) return True - except TypeError as e: + except TypeError: return False diff --git a/src/paddlefx/variables/callable.py b/src/paddlefx/variables/callable.py index 936da82..caa5e75 100644 --- a/src/paddlefx/variables/callable.py +++ b/src/paddlefx/variables/callable.py @@ -67,7 +67,7 @@ def __call__(self, tx: PyEvalBase, *args: VariableBase, **kwargs) -> VariableBas return result else: # basic layer ot = type(args[0].var) - obj_cls = type(args[0]) + target = '' model = ( tx.f_locals['self'] if 'self' in tx.f_locals else globals()['self'] @@ -82,7 +82,7 @@ def __call__(self, tx: PyEvalBase, *args: VariableBase, **kwargs) -> VariableBas elif fn.__module__.startswith("paddle"): # TODO: support multiple ouputs and containers ot = type(args[0].var) - obj_cls = type(args[0]) + output = graph.call_function(fn, args, kwargs, ot) return TensorVariable(None, node=output) elif inspect.isbuiltin(fn): @@ -95,7 +95,7 @@ def __call__(self, tx: PyEvalBase, *args: VariableBase, **kwargs) -> VariableBas if isinstance(attr, types.MethodType): # For method variables ot = type(args[0].var) - obj_cls = type(args[0]) + return CallableVariable(fn, tx=tx) else: # the attr could be callable function @@ -110,17 +110,17 @@ def __call__(self, tx: PyEvalBase, *args: VariableBase, **kwargs) -> VariableBas operator.iadd, ]: ot = type(args[0].var) - obj_cls = type(args[0]) + output = graph.call_function(fn, args, kwargs, ot) return TensorVariable(None, node=output) elif fn in [operator.gt, operator.lt, operator.ge, operator.le]: ot = type(args[0].var) - obj_cls = type(args[0]) + output = graph.call_function(fn, args, kwargs, ot) return TensorVariable(None, node=output) elif fn in [operator.is_, operator.is_not]: ot = type(args[0].var) - obj_cls = type(args[0]) + output = graph.call_function(fn, args, kwargs, ot) return TensorVariable(None, node=output) else: