From b18b5f121fc53dc767b0e1790f5acd34281fb073 Mon Sep 17 00:00:00 2001 From: Yifan Zhao <yifanz16@illinois.edu> Date: Mon, 1 Feb 2021 04:22:53 -0600 Subject: [PATCH] Finished generating model metadata --- .../torch2hpvm/torch2hpvm/approxknobs.json | 63 ++++++++-------- .../projects/torch2hpvm/torch2hpvm/compile.py | 74 ++++++++++++++----- .../torch2hpvm/torch2hpvm/graph_ir.py | 13 +++- 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/hpvm/projects/torch2hpvm/torch2hpvm/approxknobs.json b/hpvm/projects/torch2hpvm/torch2hpvm/approxknobs.json index 2462a512f2..974b536c48 100644 --- a/hpvm/projects/torch2hpvm/torch2hpvm/approxknobs.json +++ b/hpvm/projects/torch2hpvm/torch2hpvm/approxknobs.json @@ -2,206 +2,203 @@ { "name": "11", "speedup": 1.0, - "applies_to": [ - "Conv2D", - "MatMul" - ] + "applies_to": null }, { "name": "12", "speedup": 1.5, "applies_to": [ - "Conv2D", - "MatMul" + "convolution", + "linear" ] }, { "name": "151", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "152", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "153", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "154", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "155", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "156", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "157", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "158", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "159", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "160", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "161", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "162", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "163", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "164", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "165", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "166", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "167", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "168", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "261", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "262", "speedup": 3.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "263", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "264", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "265", "speedup": 2.25, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "266", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "267", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "268", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] }, { "name": "269", "speedup": 2.0, "applies_to": [ - "Conv2D" + "convolution" ] } ] diff --git a/hpvm/projects/torch2hpvm/torch2hpvm/compile.py b/hpvm/projects/torch2hpvm/torch2hpvm/compile.py index 5b8cb3e1f6..bf1da0270b 100644 --- a/hpvm/projects/torch2hpvm/torch2hpvm/compile.py +++ b/hpvm/projects/torch2hpvm/torch2hpvm/compile.py @@ -1,7 +1,7 @@ import os from pathlib import Path from tempfile import NamedTemporaryFile -from typing import IO, NamedTuple, Optional, Sequence, Tuple, Union +from typing import Dict, IO, List, NamedTuple, Optional, Sequence, Tuple, Union import onnx import torch @@ -33,6 +33,7 @@ class ModelExporter: testset_name = "test_input.bin", "test_labels.bin" weight_dir_name = "weights" source_file_name = "hpvm_c.cpp" + metadata_file_name = "ops.json" def __init__( self, @@ -72,34 +73,64 @@ class ModelExporter: def export_datasets(self): input_, labels = self.tuneset_name - self._dump_dataset(self.tune_dataset, self.weight_dir / input_, self.weight_dir / labels) + self._dump_dataset( + self.tune_dataset, self.weight_dir / input_, self.weight_dir / labels + ) input_, labels = self.testset_name - self._dump_dataset(self.test_dataset, self.weight_dir / input_, self.weight_dir / labels) + self._dump_dataset( + self.test_dataset, self.weight_dir / input_, self.weight_dir / labels + ) def export_metadata( - self, - output: PathLike = None, approx_knobs_file: PathLike = def_approx_knobs_file + self, output: PathLike, approx_knobs_file: PathLike = def_approx_knobs_file ): import json from collections import defaultdict with Path(approx_knobs_file).open() as f: knobs = json.load(f) - ty_knobs = defaultdict(list) + KnobInfoT = Tuple[str, float] + ty_knobs: Dict[str, List[KnobInfoT]] = defaultdict(list) + default_knobs: List[KnobInfoT] = [] for k in knobs: - for ty in k.pop("applies_to"): - ty_knobs[ty].append((k["name"], k["speedup"])) - knobs_used = set() + applies_to = k.pop("applies_to") + k = k["name"], k["speedup"] + if applies_to is None: + default_knobs.append(k) + continue + for ty in applies_to: + ty_knobs[ty].append(k) + idx = 0 + op_cost: Dict[str, int] = {} + op_knobs: Dict[str, List[str]] = {} + knob_speedup: Dict[str, float] = {} for node in self.dfg.traverse_order: - knobs = ty_knobs.get(node.op_type, []) - flops = node.get_flops() - knobs_used.update(knobs) - print(f"{node.name} ({node.op_type}) -> {knobs}, {flops}") + if not node.hpvm_op_type: + continue + hpvm_op_name = f"{node.hpvm_op_type}_{idx}" + type_knobs = ty_knobs.get(node.hpvm_op_type, []) + this_op_knobs = type_knobs + default_knobs + knobs_speedup = dict(this_op_knobs) + op_cost[hpvm_op_name] = int(node.get_flops()) # May get np.int64 + op_knobs[hpvm_op_name] = list(knobs_speedup.keys()) + knob_speedup.update(knobs_speedup) + idx += 1 + with Path(output).open("w") as f: + json.dump( + { + "op_cost": op_cost, + "knob_speedup": knob_speedup, + "op_knobs": op_knobs, + }, + f, + indent=2, + ) def export_all(self, output: PathLike = None, batch_size: Optional[int] = None): default_codefile = self.output_dir / self.source_file_name self.export_source_code(output or default_codefile, batch_size) - self.export_metadata() + default_metafile = self.output_dir / self.metadata_file_name + self.export_metadata(default_metafile) self.export_weights() self.export_datasets() @@ -121,7 +152,9 @@ class ModelExporter: inputs.tofile(labels_filename) @classmethod - def _check_datasets(cls, tune_dataset: DatasetTy, test_dataset: DatasetTy) -> Tuple[int, int, int, int]: + def _check_datasets( + cls, tune_dataset: DatasetTy, test_dataset: DatasetTy + ) -> Tuple[int, int, int, int]: tune_shape = cls._check_dataset_get_shape(tune_dataset) test_shape = cls._check_dataset_get_shape(test_dataset) if tune_shape != test_shape: @@ -137,9 +170,14 @@ class ModelExporter: if isinstance(dataset, Dataset): size = len(dataset) sample = dataset[0] - if not isinstance(sample, (np.ndarray, torch.Tensor)) or len(sample.shape) != 4: - raise ValueError("Dataset must be a 4D tensor due to backend limitation") - return size, *sample.shape + if ( + not isinstance(sample, (np.ndarray, torch.Tensor)) + or len(sample.shape) != 4 + ): + raise ValueError( + "Dataset must be a 4D tensor due to backend limitation" + ) + return [size, *sample.shape] if not isinstance(dataset, BinDataset): raise TypeError("Only BinDataset or PyTorch Dataset are supported") input_file = Path(dataset.input_file) diff --git a/hpvm/projects/torch2hpvm/torch2hpvm/graph_ir.py b/hpvm/projects/torch2hpvm/torch2hpvm/graph_ir.py index 39b6873e19..3309072723 100644 --- a/hpvm/projects/torch2hpvm/torch2hpvm/graph_ir.py +++ b/hpvm/projects/torch2hpvm/torch2hpvm/graph_ir.py @@ -15,6 +15,7 @@ class DFGNode(abc.ABC): """ op_type = "" + hpvm_op_type = "" def __init__( self, name: str, input_shapes: Sequence[ShapeT], output_shape: ShapeT, **kwargs @@ -114,6 +115,7 @@ class WeightTensor(TensorNode): class Conv2DNode(DFGNode): op_type = "Conv2D" + hpvm_op_type = "convolution" def __init__( self, @@ -205,15 +207,18 @@ class _Pool2DNode(DFGNode, abc.ABC): class MaxPool2DNode(_Pool2DNode): pool_type = "0" op_type = "MaxPool2D" + hpvm_op_type = "maxpool" class AveragePool2DNode(_Pool2DNode): pool_type = "1" op_type = "AveragePool2D" + hpvm_op_type = "avgpool" class BiasAddNode(DFGNode): op_type = "BiasAdd" + hpvm_op_type = "add" def codegen(self): return "tensorAdd", [] @@ -224,6 +229,7 @@ class BiasAddNode(DFGNode): class MatMulNode(DFGNode): op_type = "MatMul" + hpvm_op_type = "linear" def codegen(self): return "tensorGemmGPU", [] @@ -265,6 +271,7 @@ class MatMulNode(DFGNode): class SoftMaxNode(DFGNode): op_type = "SoftMax" + hpvm_op_type = "softmax" def codegen(self): return "tensorSoftmax", [] @@ -275,6 +282,7 @@ class SoftMaxNode(DFGNode): class AddNode(DFGNode): op_type = "Add" + hpvm_op_type = "add" def codegen(self): return "tensorAdd", [] @@ -285,6 +293,7 @@ class AddNode(DFGNode): class ReluNode(DFGNode): op_type = "ReLU" + hpvm_op_type = "relu" def codegen(self): return "tensorRelu", [] @@ -295,6 +304,7 @@ class ReluNode(DFGNode): class TanhNode(DFGNode): op_type = "Tanh" + hpvm_op_type = "tanh" def codegen(self): return "tensorTanh", [] @@ -304,7 +314,8 @@ class TanhNode(DFGNode): class BatchNormalizationNode(DFGNode): - op_type = "BN" + op_type = "BatchNorm" + hpvm_op_type = "batchnorm" def __init__( self, -- GitLab