예제 #1
0
 def __init__(self, smtlib_property: SMTLIBProperty, x_name: str,
              y_name: str):
     self.smtlib_property = smtlib_property
     self.x_name = x_name
     self.y_name = y_name
     self.x = self.get_components_of(self.x_name)
     self.y = self.get_components_of(self.y_name)
     self.in_coef_mat = Tensor([])
     self.in_bias_mat = Tensor([])
     self.out_coef_mat = []
     self.out_bias_mat = []
예제 #2
0
def text_to_tensor_set(text: str) -> tuple:
    """
    This method takes a string in format "(n,m,l), (n,m,l), ..."
    where n, m, l are integers and converts it into a tuple containing
    the set of Tensors with the given dimensions.

    Parameters
    ----------
    text: str
        Input string to convert.
    Returns
    ----------
    tuple
        The converted tensor set.

    """

    tensors = tuple()
    temp = tuple()

    for token in text.split(", "):
        num = int(token.replace("(", "").replace(")", ""))
        temp += (num, )
        if ")" in token:
            tensors += (Tensor(shape=temp,
                               buffer=np.random.normal(size=temp)), )

    return tensors
예제 #3
0
def text_to_tensor(text: str) -> Tensor:
    """
    This method takes a string in format "n,m,l" with n, m, l
    are integers and converts it into a Tensor with the
    given dimensions.

    Parameters
    ----------
    text : str
        Input string to convert.
    Returns
    ----------
    Tensor
        The converted tensor.

    """

    dims = ()
    num = 0

    for c in text:
        if '0' <= c <= '9':
            num = (num * 10) + int(c)
        else:
            dims += (num, )
            num = 0
    dims += (num, )

    return Tensor(shape=dims, buffer=np.random.normal(size=dims))
예제 #4
0
def compute_saliency(net: networks.NeuralNetwork, ref_input: Tensor):
    class BackHook:
        def __init__(self, module: torch.nn.Module, backward=True):
            if backward:
                self.hook = module.register_backward_hook(self.hook_fn)
            else:
                self.hook = module.register_forward_hook(self.hook_fn)
            self.m_input = None
            self.m_output = None

        def hook_fn(self, module, m_input, m_output):
            self.m_input = m_input
            self.m_output = m_output

        def close(self):
            self.hook.remove()

    py_net = cv.PyTorchConverter().from_neural_network(net).pytorch_network

    # We register the hooks on the modules of the networks
    backward_hooks = [BackHook(layer) for layer in py_net.modules()]
    forward_hooks = [BackHook(layer, False) for layer in py_net.modules()]

    ref_input = torch.from_numpy(ref_input)
    ref_input.requires_grad = True
    out = py_net(ref_input)
    i = 0
    print("FORWARD HOOKS")
    for m in py_net.modules():
        hook = forward_hooks[i]
        print(m)
        print("INPUT")
        print(hook.m_input)
        print("OUTPUT")
        print(hook.m_output)
        i = i + 1
    for k in range(len(out)):
        print(f"Variable {k} of output")
        out = py_net(ref_input)
        out[k].backward(retain_graph=True)
        print("INPUT GRAD:" + f"{ref_input.grad}")

        i = 0
        for m in py_net.modules():
            hook = backward_hooks[i]
            print(m)
            print("INPUT")
            print(hook.m_input[0])
            print("OUTPUT")
            print(hook.m_output[0])
            i = i + 1

    print(out)
    ref_input[0] = ref_input[0] + 10
    out = py_net(ref_input)
    print(out)
예제 #5
0
def generate_untargeted_linf_robustness_query(data: Tensor, target: int,
                                              bounds: tuple, num_classes: int,
                                              epsilon: float, filepath: str):
    """
    Function to generate an untargeted Robustness SMTLIB query and to save it to a SMTLIB file.
    The robustness query is of the kind based on the infinity norm.
    It assumes that the data and target are from a classification task.

    Parameters
    ----------
    data : Tensor
        Input data of interest.
    adv_target : int
        Desired adversarial target for the input data.
    bounds : (int, int)
        Bounds for the input data (lower_bound, upper_bound).
    num_classes : int
        Number of possible classes.
    epsilon : float
        Perturbation with respect to the infinity norm.
    filepath : str
        Filepath for the resulting SMTLIB file.

    """
    with open(filepath, "w") as f:

        flattened_data = data.flatten()
        for i in range(len(flattened_data)):
            f.write(f"(declare-const X_{i} Real)\n")

        for i in range(num_classes):
            f.write(f"(declare-const Y_{i} Real)\n")

        for i in range(len(flattened_data)):

            if flattened_data[i] - epsilon < bounds[0]:
                f.write(f"(assert (>= X_{i} {bounds[0]}))\n")
            else:
                f.write(f"(assert (>= X_{i} {flattened_data[i] - epsilon}))\n")

            if flattened_data[i] + epsilon > bounds[1]:
                f.write(f"(assert (<= X_{i} {bounds[1]}))\n")
            else:
                f.write(f"(assert (<= X_{i} {flattened_data[i] + epsilon}))\n")

        output_query = "(assert (or"
        for i in range(num_classes):

            if i != target:
                output_query += f" (<= (- Y_{target} Y_{i}) 0)"

        output_query += "))"
        f.write(output_query)
예제 #6
0
    def edit_node(self, block: NodeBlock):
        """
        This method propagates the changes stored in the block.edits
        attribute.

        Parameters
        ----------
        block : NodeBlock
            The block to update.

        """

        edits = block.edits
        if edits is not None and block.block_id in self.renderer.disconnected_network.keys(
        ):
            edit_node_id = edits[0]
            edit_data = edits[1]
            new_in_dim = None
            if "in_dim" in edit_data.keys():
                new_in_dim = edit_data["in_dim"]

            # If in_dim changes in FC, update in_features
            if block.node.name == 'Fully Connected' and new_in_dim is not None:
                edit_data["in_features"] = new_in_dim[-1]

            # If out_features changes in FC, update out_dim
            if block.node.name == 'Fully Connected' and 'out_features' in edit_data.keys(
            ):
                edit_data["out_dim"] = block.out_dim[:-1] + (
                    edit_data["out_features"], )

            for block_par, info in block.node.param.items():
                if "shape" in info:
                    str_shape = tuple(map(str, info["shape"].split(', ')))
                    new_shape = tuple()  # Confront
                    for dim in str_shape:
                        new_dim = block.block_data[dim]
                        if dim in edit_data:
                            new_dim = edit_data[dim]
                        if isinstance(new_dim, tuple):
                            new_shape += new_dim
                        else:
                            new_shape += (new_dim, )

                    # Add new Tensor value to edit_data
                    edit_data[block_par] = Tensor(
                        shape=new_shape,
                        buffer=np.random.normal(size=new_shape))

            try:  # Check if the network has changed
                self.renderer.edit_node(edit_node_id, edit_data)
            except Exception as e:
                dialog = MessageDialog(
                    str(e) + "\nImpossible to propagate changes.",
                    MessageType.ERROR)
                dialog.exec()

            # Update the graphic block
            self.renderer.disconnected_network[edit_node_id].update_labels()

            # Update dimensions in edges & nodes
            for line in self.scene.edges:
                if isinstance(self.scene.blocks[line.origin], NodeBlock):
                    origin_id = self.scene.blocks[line.origin].block_id
                    new_dim = self.renderer.NN.nodes[origin_id].out_dim
                    line.update_dims(new_dim)
                    self.scene.blocks[line.origin].out_dim = new_dim
                    self.scene.blocks[line.destination].in_dim = new_dim

            # Empty changes buffer
            block.edits = None
예제 #7
0
    def init_layout(self) -> None:
        """
        This method sets up the the node block main_layout with
        attributes and values.

        """

        self.init_grid()

        # Iterate and display parameters, count rows
        par_labels = dict()
        count = 1
        for name, param in self.node.param.items():
            # Set the label
            par_labels[name] = CustomLabel(name)
            par_labels[name].setAlignment(Qt.AlignLeft)
            par_labels[name].setStyleSheet(style.PAR_NODE_STYLE)

            self.dim_labels[name] = CustomLabel()
            self.dim_labels[name].setAlignment(Qt.AlignCenter)
            self.dim_labels[name].setStyleSheet(style.DIM_NODE_STYLE)

            self.content_layout.addWidget(par_labels[name], count, 0)
            self.content_layout.addWidget(self.dim_labels[name], count, 1)
            count += 1

            # Init block data with default values
            if "default" in param.keys() and param["default"] == "None":
                self.block_data[name] = None
            elif param["type"] == "Tensor":
                if "shape" in param.keys():
                    shape = self.text_to_tuple(param["shape"])
                    self.block_data[name] = Tensor(
                        shape=shape, buffer=np.random.normal(size=shape))
                else:
                    self.block_data[name] = Tensor(
                        shape=(1, 1), buffer=np.random.normal(size=(1, 1)))
            elif param["type"] == "int":
                if "default" in param.keys():
                    if param["default"] == "rand":
                        self.block_data[name] = 1
                    else:
                        self.block_data[name] = int(param["default"])
                else:
                    self.block_data[name] = 1
            elif param["type"] == "list of ints":
                if "default" in param.keys():
                    self.block_data[name] = tuple(
                        map(int, param["default"].split(', ')))
                else:
                    self.block_data[name] = (1, 1)
            elif param["type"] == "float":
                if "default" in param.keys():
                    if param["default"] == "rand":
                        self.block_data[name] = 1
                    else:
                        self.block_data[name] = float(param["default"])
                else:
                    self.block_data[name] = 0.1
            elif param["type"] == "boolean":
                if "default" in param.keys():
                    self.block_data[name] = bool(param["default"])
                else:
                    self.block_data[name] = False

        self.update_labels()
        self.edited.connect(lambda: self.update_labels())