From 53295dc212a7a0d34949e196cab33a844e5ce035 Mon Sep 17 00:00:00 2001 From: Felipe Date: Wed, 29 Jun 2022 12:49:23 -0400 Subject: [PATCH 1/4] Added operations --- dnnf/pytorch.py | 107 +++++++++++++++++++++++++++++++++++++++++++--- dnnf/reduction.py | 1 + dnnf/utils.py | 19 ++++++++ 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/dnnf/pytorch.py b/dnnf/pytorch.py index 5e29d69..42066cc 100644 --- a/dnnf/pytorch.py +++ b/dnnf/pytorch.py @@ -4,6 +4,7 @@ import torch import torch.nn.functional as F from dnnv.nn import Operation, OperationGraph, OperationVisitor, operations +from .utils import ONNX_TO_TORCH_DTYPE def convert(op_graph: OperationGraph) -> PytorchModel: @@ -230,14 +231,25 @@ def flatten(operation_graph): return flatten + # def visit_Gather(self, operation: operations.Gather): + # self.generic_visit(operation) + + # def gather(operation_graph): + # x = torch.as_tensor(operation_graph[operation.x]) + # axis = int(operation.axis) + # indices = torch.as_tensor(operation_graph[operation.indices]) + # result = torch.gather(x, axis, indices) + # return result + + # return gather def visit_Gather(self, operation: operations.Gather): self.generic_visit(operation) def gather(operation_graph): x = torch.as_tensor(operation_graph[operation.x]) - axis = int(operation.axis) - indices = torch.as_tensor(operation_graph[operation.indices]) - result = torch.gather(x, axis, indices) + indices = [slice(None)] * x.ndim + indices[operation.axis] = operation.indices + result = x[indices] return result return gather @@ -407,12 +419,12 @@ def split(operation_graph): def visit_Sub(self, operation: operations.Sub): self.generic_visit(operation) - def add(operation_graph): + def sub(operation_graph): a = operation_graph[operation.a] b = operation_graph[operation.b] return a - b - return add + return sub def visit_Tanh(self, operation: operations.Tanh): self.generic_visit(operation) @@ -445,5 +457,90 @@ def unsqueeze(operation_graph): return unsqueeze + def visit_Upsample(self, operation: operations.Upsample): + self.generic_visit(operation) + + def upsample(operation_graph): + x = operation_graph[operation.x] + scales = operation.scales.tolist() + mode = operation.mode + result = torch.nn.Upsample(scale_factor=tuple(scales[2:]), mode=mode)(x) + # result = F.interpolate(x, scale_factor=scales, mode=mode) + return result + + return upsample + + def visit_Div(self, operation: operations.Div): + self.generic_visit(operation) + + def div(operation_graph): + a = operation_graph[operation.a] + b = operation_graph[operation.b] + result = torch.div(a, b) + return result + + return div + + def visit_Squeeze(self, operation: operations.Squeeze): + self.generic_visit(operation) + + def squeeze(operation_graph): + x = operation_graph[operation.x] + axes = operation.axes + if axes is None: + result = torch.squeeze(x) + else: + result = torch.squeeze(x, dim=axes) + return result + + return squeeze + + def visit_Expand(self, operation: operations.Expand): + self.generic_visit(operation) + + def expand(operation_graph): + x = operation_graph[operation.x] + shape = operation_graph[operation.shape] + result = x.expand(shape) + return result + + return expand + + def visit_Clip(self, operation: operations.Clip): + self.generic_visit(operation) + + def clip(operation_graph): + x = operation_graph[operation.x] + _min = operation.min + _max = operation.max + result = torch.clip(x, _min, _max) + return result + + return clip + + def visit_ReduceL2(self, operation: operations.ReduceL2): + self.generic_visit(operation) + + def reducel2(operation_graph): + x = operation_graph[operation.x] + axes = operation.axes + keepdims = operation.keepdims + result = torch.norm(x, p=2, dim=axes, keepdim=bool(keepdims)) + return result + + return reducel2 + + def visit_Cast(self, operation: operations.Cast): + self.generic_visit(operation) + + def cast(operation_graph): + x = operation_graph[operation.x] + # x = [operation_graph[x_] for x_ in operation.x] + # if len(x) == 1: + # result = x[0].type(ONNX_TO_TORCH_DTYPE[operation.to]) + result = x.type(ONNX_TO_TORCH_DTYPE[operation.to]) + return result + + return cast __all__ = ["convert", "PytorchConverter"] diff --git a/dnnf/reduction.py b/dnnf/reduction.py index 8896a49..b5263a8 100644 --- a/dnnf/reduction.py +++ b/dnnf/reduction.py @@ -221,6 +221,7 @@ def suffixed_op_graph(self) -> OperationGraph: output_shape = self.op_graph.output_shape[0] axis = (0, 0, 1)[len(output_shape)] + # axis = 0 if len(self.op_graph.output_operations) == 1: new_output_op = self.op_graph.output_operations[0] else: diff --git a/dnnf/utils.py b/dnnf/utils.py index f565814..8724a98 100644 --- a/dnnf/utils.py +++ b/dnnf/utils.py @@ -1,12 +1,31 @@ """ """ import logging +import onnx import random import sys +import torch from typing import Optional import numpy as np +ONNX_TO_TORCH_DTYPE = { + onnx.TensorProto.DOUBLE: torch.float64, + onnx.TensorProto.FLOAT16: torch.float16, + onnx.TensorProto.FLOAT: torch.float32, + onnx.TensorProto.INT8: torch.int8, + onnx.TensorProto.INT16: torch.int16, + onnx.TensorProto.INT32: torch.int32, + onnx.TensorProto.INT64: torch.int64, + onnx.TensorProto.UINT8: torch.uint8, + # onnx.TensorProto.UINT16: torch.uint16, + # onnx.TensorProto.UINT32: torch.uint32, + # onnx.TensorProto.UINT64: torch.uint64, + onnx.TensorProto.BOOL: torch.bool, + onnx.TensorProto.COMPLEX64: torch.complex64, + onnx.TensorProto.COMPLEX128: torch.complex128, + # onnx.TensorProto.STRING: torch.string, +} def set_random_seed(seed: Optional[int]) -> None: random.seed(seed) From fe4e2fd3b9c220443adc86fdeab0e9af8c2fe784 Mon Sep 17 00:00:00 2001 From: Felipe Date: Thu, 30 Jun 2022 16:36:37 -0400 Subject: [PATCH 2/4] Added condition for hpoly_constraints --- dnnf/reduction.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/dnnf/reduction.py b/dnnf/reduction.py index b5263a8..68b0b41 100644 --- a/dnnf/reduction.py +++ b/dnnf/reduction.py @@ -337,22 +337,23 @@ def add_constraint(self, variables, indices, coeffs, b, is_open): self.interval_constraints[0][flat_index] = max(b / coeff, current_bound) def build(self) -> HPolyProperty: - Ab = np.vstack(self.hpoly_constraints) - A = Ab[..., :-1] - b = Ab[..., -1:] - bounds = tuple(zip(*self.interval_constraints)) - for i in range(self.num_vars): - c = np.zeros(self.num_vars) - c[i] = 1 - result = linprog(c, A, b, bounds=bounds, method="highs") - if result.success: - current_bound = self.interval_constraints[0][i] - self.interval_constraints[0][i] = max(result.x[i], current_bound) - c[i] = -1 - result = linprog(c, A, b, bounds=bounds, method="highs") - if result.success: - current_bound = self.interval_constraints[1][i] - self.interval_constraints[1][i] = min(result.x[i], current_bound) + if self.hpoly_constraints: + Ab = np.vstack(self.hpoly_constraints) + A = Ab[..., :-1] + b = Ab[..., -1:] + bounds = tuple(zip(*self.interval_constraints)) + for i in range(self.num_vars): + c = np.zeros(self.num_vars) + c[i] = 1 + result = linprog(c, A, b, bounds=bounds, method="highs") + if result.success: + current_bound = self.interval_constraints[0][i] + self.interval_constraints[0][i] = max(result.x[i], current_bound) + c[i] = -1 + result = linprog(c, A, b, bounds=bounds, method="highs") + if result.success: + current_bound = self.interval_constraints[1][i] + self.interval_constraints[1][i] = min(result.x[i], current_bound) return HPolyProperty.build( self.input_vars, self.output_vars, From 648cc9165bdef37b50d647f81c8d75c9a628e55b Mon Sep 17 00:00:00 2001 From: Felipe Date: Thu, 30 Jun 2022 16:41:54 -0400 Subject: [PATCH 3/4] Added operations --- dnnf/pytorch.py | 16 +--------------- dnnf/reduction.py | 3 +-- dnnf/utils.py | 5 +---- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/dnnf/pytorch.py b/dnnf/pytorch.py index 42066cc..196cddc 100644 --- a/dnnf/pytorch.py +++ b/dnnf/pytorch.py @@ -231,17 +231,6 @@ def flatten(operation_graph): return flatten - # def visit_Gather(self, operation: operations.Gather): - # self.generic_visit(operation) - - # def gather(operation_graph): - # x = torch.as_tensor(operation_graph[operation.x]) - # axis = int(operation.axis) - # indices = torch.as_tensor(operation_graph[operation.indices]) - # result = torch.gather(x, axis, indices) - # return result - - # return gather def visit_Gather(self, operation: operations.Gather): self.generic_visit(operation) @@ -465,7 +454,6 @@ def upsample(operation_graph): scales = operation.scales.tolist() mode = operation.mode result = torch.nn.Upsample(scale_factor=tuple(scales[2:]), mode=mode)(x) - # result = F.interpolate(x, scale_factor=scales, mode=mode) return result return upsample @@ -535,12 +523,10 @@ def visit_Cast(self, operation: operations.Cast): def cast(operation_graph): x = operation_graph[operation.x] - # x = [operation_graph[x_] for x_ in operation.x] - # if len(x) == 1: - # result = x[0].type(ONNX_TO_TORCH_DTYPE[operation.to]) result = x.type(ONNX_TO_TORCH_DTYPE[operation.to]) return result return cast + __all__ = ["convert", "PytorchConverter"] diff --git a/dnnf/reduction.py b/dnnf/reduction.py index 68b0b41..a9adbad 100644 --- a/dnnf/reduction.py +++ b/dnnf/reduction.py @@ -220,8 +220,7 @@ def suffixed_op_graph(self) -> OperationGraph: import dnnv.nn.operations as operations output_shape = self.op_graph.output_shape[0] - axis = (0, 0, 1)[len(output_shape)] - # axis = 0 + axis = 0 if len(self.op_graph.output_operations) == 1: new_output_op = self.op_graph.output_operations[0] else: diff --git a/dnnf/utils.py b/dnnf/utils.py index 8724a98..187bc65 100644 --- a/dnnf/utils.py +++ b/dnnf/utils.py @@ -18,15 +18,12 @@ onnx.TensorProto.INT32: torch.int32, onnx.TensorProto.INT64: torch.int64, onnx.TensorProto.UINT8: torch.uint8, - # onnx.TensorProto.UINT16: torch.uint16, - # onnx.TensorProto.UINT32: torch.uint32, - # onnx.TensorProto.UINT64: torch.uint64, onnx.TensorProto.BOOL: torch.bool, onnx.TensorProto.COMPLEX64: torch.complex64, onnx.TensorProto.COMPLEX128: torch.complex128, - # onnx.TensorProto.STRING: torch.string, } + def set_random_seed(seed: Optional[int]) -> None: random.seed(seed) np.random.seed(seed) From b3d5836cec564e9d12e31fe43bc184a0604cbf19 Mon Sep 17 00:00:00 2001 From: Felipe Date: Sat, 2 Jul 2022 14:15:38 -0400 Subject: [PATCH 4/4] Reverting change. Changing this line will require taking a deeper look. --- dnnf/reduction.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnnf/reduction.py b/dnnf/reduction.py index a9adbad..a5967c5 100644 --- a/dnnf/reduction.py +++ b/dnnf/reduction.py @@ -220,7 +220,8 @@ def suffixed_op_graph(self) -> OperationGraph: import dnnv.nn.operations as operations output_shape = self.op_graph.output_shape[0] - axis = 0 + # axis = 0 + axis = (0, 0, 1)[len(output_shape)] if len(self.op_graph.output_operations) == 1: new_output_op = self.op_graph.output_operations[0] else: