Skip to content

Commit

Permalink
Merge pull request #54 from InfiniTensor/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
YdrMaster authored Dec 6, 2023
2 parents c162ed4 + a79cc33 commit 1600518
Show file tree
Hide file tree
Showing 95 changed files with 2,537 additions and 967 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

使用 `make install-python` 编译并安装 Python 前端到全局,安装的包名为 `refactor_grpah`

环境变量:

- 添加 `TYPE=Debug``TYPE=Release` 以启用指定的优化级别,默认为 `Debug`
- 添加 `CUDA=OFF``CUDA=ON` 以打开或关闭英伟达显卡支持,默认为 `OFF`

## 使用前端

```python
Expand Down
79 changes: 79 additions & 0 deletions scripts/compare/compare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import argparse
import numpy as np
import os


def parse_args():
parser = argparse.ArgumentParser(description="Compare output files.")
parser.add_argument(
"--expect",
type=str,
default="./onnx_outputs/",
help="Path to the expected output files by onnx_runtime.",
)
parser.add_argument(
"--actual",
type=str,
default="./if_outputs/",
help="Path to the actual output files.",
)
args = parser.parse_args()
return (
args.expect,
args.actual,
)

def getDiff(base, test):
absolute_diff = np.subtract(base, test)
max_absolute_diff = np.max(np.abs(absolute_diff))

baseCopy = base.astype(np.float64).ravel()
testCopy = test.astype(np.float64).ravel()
upValue = np.sum(np.abs(baseCopy - testCopy))
downValue = np.sum(np.abs(baseCopy)) + np.float64(1e-9)
max_relative_diff = upValue / downValue

return max_absolute_diff, max_relative_diff

def compare_npy(actual_path, expect_path, edge, node):
actual = np.load(actual_path)
expect = np.load(expect_path)
if np.isnan(actual).any():
print(f"NAN value in node:{node} edge:{edge}")
return

max_absolute_diff, max_relative_diff = getDiff(expect, actual)
if max_absolute_diff != 0.0: ## No need to print tensor with no diff
print(f'{max_absolute_diff}\t{max_relative_diff}\t{node}\t{edge}')


def main():
expect_dir, actual_dir = parse_args()
meta_files = sorted([f for f in os.listdir(actual_dir) if f.endswith(".meta")])
for meta_file in meta_files:
with open(os.path.join(actual_dir, meta_file), "r") as file:
node_name = ""
for line in file:
elements = line.strip().split()
if "node" == elements[0]:
node_id, node_name = elements[1], elements[2]
elif ("input" == elements[0] or "output" == elements[0]) and len(
elements
) == 4:
edge_id, edge_name, actual_file_path = (
elements[1],
elements[2],
elements[3],
)
expect_file = edge_name.replace("/", "_")
expect_file = expect_file.replace(".", "-")
expect_file = expect_file + ".npy"
expect_file_path = os.path.join(expect_dir, expect_file)
if os.path.exists(expect_file_path):
compare_npy(
actual_file_path, expect_file_path, edge_name, node_name
)


if __name__ == "__main__":
main()
68 changes: 68 additions & 0 deletions scripts/compare/run_actual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import numpy as np
from pathlib import Path
from onnx import load
from refactor_graph.onnx import make_compiler
import argparse
import os
import shutil

input_dir_name = "inputs/"
result_dir_name = "if_outputs/"


def parse_args():
parser = argparse.ArgumentParser(
description="Run with onnx_runtime, export all outputs to file."
)
parser.add_argument(
"--model", type=str, required=True, help="Path to the ONNX model file."
)
parser.add_argument("--output", type=str, default="./", help="Working directory.")

parser.add_argument(
"--gen_input", action="store_true", help="Generate random input."
)
args = parser.parse_args()
print("arg setting: ", args)
return (
args.model,
args.output,
args.gen_input,
)


def create_dir(working_path, dir_name):
dir_path = os.path.join(working_path, dir_name)
if os.path.exists(dir_path):
shutil.rmtree(dir_path)
os.mkdir(dir_path)
else:
os.mkdir(dir_path)

return dir_path


def main():
model_path, work_path, gen_input = parse_args()
if gen_input:
create_dir(work_path, input_dir_name)
create_dir(work_path, result_dir_name)

model = load(model_path, load_external_data=False)
compiler = make_compiler(model, Path(model_path).parent.__str__())
executor = compiler.compile("cuda", "default", [])
inputs = compiler.zero_inputs()

for i, input in enumerate(inputs):
if gen_input:
input[...] = np.random.random(input.shape).astype(input.dtype)
executor.set_input(i, input)
np.save(os.path.join(work_path, input_dir_name, f"input_{i}"), input)
else:
input = np.load(os.path.join(work_path, input_dir_name, f"input_{i}.npy"))
executor.set_input(i, input)
executor.trace(os.path.join(work_path, result_dir_name), "npy")


if __name__ == "__main__":
main()
140 changes: 140 additions & 0 deletions scripts/compare/run_onnx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import argparse
import onnx
import numpy as np
import onnxruntime
import os
import shutil
from onnx.shape_inference import infer_shapes

input_dir_name = "inputs/"
onnx_result_dir_name = "onnx_outputs/"
size_threshold = 1024 * 1024 * 1024


def parse_args():
parser = argparse.ArgumentParser(
description="Run with onnx_runtime, export all outputs to file."
)
parser.add_argument(
"--model", type=str, required=True, help="Path to the ONNX model file."
)
parser.add_argument("--output", type=str, default="./", help="Working directory.")
parser.add_argument(
"--gen_input", action="store_true", help="Generate random input."
)
args = parser.parse_args()
print("arg setting: ", args)
return (
args.model,
args.output,
args.gen_input,
)


def gen_inputs(model, working_path):
inputs_info = model.graph.input
dir_path = create_dir(working_path, input_dir_name)
inputs = {}
initializers = set(i.name for i in model.graph.initializer)

for i, info in enumerate(inputs_info):
if info.name not in initializers:
shape = [
d.dim_value if d.HasField("dim_value") else 1
for d in info.type.tensor_type.shape.dim
]

if info.type.tensor_type.elem_type == 6:
data = np.random.randint(0, 2, size=shape).astype(np.int32)
elif info.type.tensor_type.elem_type == 7:
data = np.random.randint(0, 2, size=shape)
else:
data = np.random.random(size=shape).astype(np.float32)
inputs[info.name] = data
np.save(os.path.join(dir_path, f"input_{i}"), data)

return inputs


def load_inputs(model, working_path):
inputs_info = model.graph.input
dir_path = os.path.join(working_path, input_dir_name)
inputs = {}
for i, info in enumerate(inputs_info):
file_path = os.path.join(dir_path, f"input_{i}.npy")
inputs[info.name] = np.load(file_path)
return inputs


def create_dir(working_path, dir_name):
dir_path = os.path.join(working_path, dir_name)
if os.path.exists(dir_path):
shutil.rmtree(dir_path)
os.mkdir(dir_path)
else:
os.mkdir(dir_path)

return dir_path


def get_extra_output_groups(model):
output_groups = []
group = []
total_size = 0
for value_info in model.graph.value_info:
group.append(value_info)
shape = [
d.dim_value if d.HasField("dim_value") else 1
for d in value_info.type.tensor_type.shape.dim
]
size = 1
for i in shape:
size *= i
total_size += size

if total_size > size_threshold:
output_groups.append(group)
group = []
total_size = 0
if total_size != 0:
output_groups.append(group)
output_groups.append([out for out in model.graph.output])
return output_groups


def run_with_extra_outputs(model, extra_outputs, inputs, output_path):
n = len(model.graph.output)
for _ in range(n):
model.graph.output.remove(model.graph.output[0])
model.graph.output.extend(extra_outputs)
output_names = [info.name for info in extra_outputs]
session = onnxruntime.InferenceSession(model.SerializeToString())
tensors = session.run(output_names=output_names, input_feed=inputs)

for output_name, tensor in zip(output_names, tensors):
output_name = output_name.replace("/", "_")
output_name = output_name.replace(".", "-")
file_path = os.path.join(output_path, output_name)
print("Save output to " + file_path)
np.save(file_path, tensor)


def main():
model_path, working_path, gen_input = parse_args()
create_dir(working_path, onnx_result_dir_name)
model = onnx.load(model_path)
model = infer_shapes(model)
if gen_input:
inputs = gen_inputs(model, working_path)
else:
inputs = load_inputs(model, working_path)

output_groups = get_extra_output_groups(model)
output_path = os.path.join(working_path, onnx_result_dir_name)

for extra_outputs in output_groups:
run_with_extra_outputs(model, extra_outputs, inputs, output_path)


if __name__ == "__main__":
main()
23 changes: 23 additions & 0 deletions scripts/compare/validate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# Save the current working directory
original_directory=$(pwd)

# Get the directory of the script
script_directory=$(dirname "$(readlink -f "$0")")

# Change to the script's directory
cd "$script_directory"

if [ "$#" -eq 1 ]; then
echo "Validating model: $1. Random inputs will be generated."
python run_actual.py --model $1 --gen_input
python run_onnx.py --model $1
python compare.py > result.txt
echo "Compare results saved in result.txt."
else
echo "Please provide an onnx file path as a single argument."
fi

# Change back to the original working directory
cd "$original_directory"
62 changes: 0 additions & 62 deletions scripts/format.py

This file was deleted.

Loading

0 comments on commit 1600518

Please sign in to comment.