Example #1
0
def normalizeNNet(readNNetFile, writeNNetFile=None):
    weights, biases, inputMins, inputMaxes, means, ranges = readNNet(
        readNNetFile, withNorm=True)

    numInputs = weights[0].shape[0]
    numOutputs = weights[-1].shape[1]

    # Adjust weights and biases of first layer
    for i in range(numInputs):
        weights[0][i, :] /= ranges[i]
    biases[0] -= np.matmul(weights[0].T, means[:-1])

    # Adjust weights and biases of last layer
    weights[-1] *= ranges[-1]
    biases[-1] *= ranges[-1]
    biases[-1] += means[-1]

    # Nominal mean and range vectors
    means = np.zeros(numInputs + 1)
    ranges = np.ones(numInputs + 1)

    if writeNNetFile is not None:
        writeNNet(weights, biases, inputMins, inputMaxes, means, ranges,
                  writeNNetFile)
        return None
    return weights, biases
Example #2
0
def write_to_nnet(network, net_name):
    weights = np.array(network.weights)
    biases = np.array(network.biases)
    inputMins = np.array(network.inputMinimums)
    inputMaxes = np.array(network.inputMaximums)
    means = np.array(network.inputMeans)
    ranges = np.array(network.inputRanges)
    fileName = os.path.join(NNET_PATH, net_name + '.nnet')
    writeNNet(weights, biases, inputMins, inputMaxes, means, ranges, fileName)
    return fileName
Example #3
0
    def test_write(self):
        nnetFile1 = "nnet/TestNetwork.nnet"
        nnetFile2 = "nnet/TestNetwork.v2.nnet"
        testInput = np.array([1.0, 1.0, 1.0, 100.0, 1.0]).astype(np.float32)
        nnet1 = NNet(nnetFile1)
        writeNNet(nnet1.weights, nnet1.biases, nnet1.mins, nnet1.maxes,
                  nnet1.means, nnet1.ranges, nnetFile2)
        nnet2 = NNet(nnetFile2)

        eval1 = nnet1.evaluate_network(testInput)
        eval2 = nnet2.evaluate_network(testInput)

        percChangeNNet = max(abs((eval1 - eval2) / eval1)) * 100.0
        self.assertTrue(percChangeNNet < 1e-8)
        self.assertTrue(filecmp.cmp(nnetFile1, nnetFile2))
Example #4
0
def FFTF2nnet(sess,
              inputMins,
              inputMaxes,
              means,
              ranges,
              order,
              nnetFile="",
              inputName="",
              outputName=""):
    weights, biases, inputSize = FFTF2W(sess, inputName, outputName)
    # Default values for input bounds and normalization constants
    if inputMins is None: inputMins = inputSize * [np.finfo(np.float32).min]
    if inputMaxes is None: inputMaxes = inputSize * [np.finfo(np.float32).max]
    if means is None: means = (inputSize + 1) * [0.0]
    if ranges is None: ranges = (inputSize + 1) * [1.0]
    writeNNet(weights, biases, inputMins, inputMaxes, means, ranges, order,
              nnetFile)
Example #5
0
def split_nn(nn_path, layer_number, property=None):
    """
    Split nn into two nns at layer_number. Create file for each part of the nn.
    :param nn_path: Neural network file name
    :param layer_number: number of layer to split on.
    :param property: input region property. Used for gurobi to find bounds of the layer we split on.
    :return: the new nnets files.
    """
    nn = NNet(nn_path)
    mid_layer_size = nn.layerSizes[layer_number]

    weights1 = nn.weights[:layer_number]
    weights2 = nn.weights[layer_number:]
    biases1 = nn.biases[:layer_number]
    biases2 = nn.biases[layer_number:]

    mins1 = nn.mins
    maxes1 = nn.maxes

    if property is not None:
        mins2, maxes2 = get_gurobi_bounds(nn_path, property_file_to_multi_range(property), layer_number,
                                           os.getcwd() + "/gurobi_bounds/split_bounds.txt")
    else:
        mins2 = [0] * mid_layer_size
        maxes2 = [1000]*mid_layer_size

    means1 = nn.means
    last_mean = nn.means[-1]
    means1[-1] = 0
    means2 = [0] * mid_layer_size + [last_mean]
    ranges1 = nn.ranges
    last_range = nn.ranges[-1]
    ranges1[-1] = 1
    ranges2 = [1] * mid_layer_size + [last_range]

    file1 = nn_path[
            :-5] + "_part1" + ".nnet"  # split the .nnet extenstion and add it at the end
    file2 = nn_path[:-5] + "_part2" + ".nnet"
    writeNNet(weights1, biases1, mins1, maxes1, means1, ranges1, file1)
    writeNNet(weights2, biases2, mins2, maxes2, means2, ranges2, file2)
    return file1, file2
Example #6
0
    #If true, use the steeper penalty. If false, use the milder penalty
    return l


model = load_model(kerasFile, custom_objects={'asymMSE': asymMSE})

# Get a list of the model weights
model_params = model.get_weights()

# Split the network parameters into weights and biases, assuming they alternate
weights = model_params[0:len(model_params):2]
biases = model_params[1:len(model_params):2]

# Transpose weight matrices
weights = [w.T for w in weights]

## Script showing how to run pb2nnet
# Min and max values used to bound the inputs
inputMins = [0.0, -3.141593, -3.141593, 100.0, 0.0]
inputMaxes = [60760.0, 3.141593, 3.141593, 1200.0, 1200.0]

# Mean and range values for normalizing the inputs and outputs. All outputs are normalized with the same value
means = [1.9791091e+04, 0.0, 0.0, 650.0, 600.0, 7.5188840201005975]
ranges = [60261.0, 6.28318530718, 6.28318530718, 1100.0, 1200.0, 373.94992]

# Tensorflow pb file to convert to .nnet file
nnetFile = kerasFile[:-2] + 'nnet'

# Convert the file
writeNNet(weights, biases, inputMins, inputMaxes, means, ranges, nnetFile)
Example #7
0
def pb2nnet(pbFile,
            inputMins=None,
            inputMaxes=None,
            means=None,
            ranges=None,
            nnetFile="",
            inputName="",
            outputName="",
            savedModel=False,
            savedModelTags=[]):
    '''
    Write a .nnet file from a frozen Tensorflow protobuf or SavedModel

    Args:
        pbFile (str): If savedModel is false, path to the frozen graph .pb file.
                      If savedModel is true, path to SavedModel folder, which
                      contains .pb file and variables subdirectory.
        inputMins (list): Minimum values for each neural network input.
        inputMaxes (list): Maximum values for each neural network output.
        means (list): Mean value for each input and value for mean of all outputs, used for normalization
        ranges (list): Range value for each input and value for range of all outputs, used for normalization
        inputName (str, optional): Name of operation corresponding to input. Default: ""
        outputName (str, optional) Name of operation corresponding to output. Default: ""
        savedModel (bool, optional) If false, load frozen graph. If true, load SavedModel object. Default: False
        savedModelTags (list, optional) If loading a SavedModel, the user must specify tags used. Default: []
    '''

    if nnetFile == "":
        nnetFile = pbFile[:-2] + 'nnet'

    if savedModel:
        ### Read SavedModel ###
        sess = tf.Session()
        tf.saved_model.loader.load(sess, savedModelTags, pbFile)

        ### Simplify graph using outputName, which must be specified for SavedModel ###
        simp_graph_def = graph_util.convert_variables_to_constants(
            sess, sess.graph.as_graph_def(), [outputName])
        with tf.Graph().as_default() as graph:
            tf.import_graph_def(simp_graph_def, name="")
        sess = tf.Session(graph=graph)
        ### End reading SavedModel

    else:
        ### Read protobuf file and begin session ###
        with tf.gfile.GFile(pbFile, "rb") as f:
            graph_def = tf.GraphDef()
            graph_def.ParseFromString(f.read())
        with tf.Graph().as_default() as graph:
            tf.import_graph_def(graph_def, name="")
        sess = tf.Session(graph=graph)
        ### END reading protobuf ###

    ### Find operations corresponding to input and output ###
    if inputName:
        inputOp = sess.graph.get_operation_by_name(inputName)
    else:  # If there is just one placeholder, use it as input
        ops = sess.graph.get_operations()
        placeholders = [x for x in ops if x.node_def.op == 'Placeholder']
        assert len(placeholders) == 1
        inputOp = placeholders[0]
    if outputName:
        outputOp = sess.graph.get_operation_by_name(outputName)
    else:  # Assume that the last operation is the output
        outputOp = sess.graph.get_operations()[-1]

    # Recursively search for weights and bias parameters and add them to list
    # Search until the inputOp is found
    # If inputOp is not found, than the operation does not exist in the graph or does not lead to the output operation
    weights = []
    biases = []
    foundInputFlag = False
    foundInputFlag = processGraph(outputOp, inputOp, foundInputFlag, weights,
                                  biases)
    if foundInputFlag:

        # Default values for input bounds and normalization constants
        if inputMins is None:
            inputMins = inputSize * [np.finfo(np.float32).min]
        if inputMaxes is None:
            inputMaxes = inputSize * [np.finfo(np.float32).max]
        if means is None: means = (inputSize + 1) * [0.0]
        if ranges is None: ranges = (inputSize + 1) * [1.0]

        # Write NNet file
        writeNNet(weights, biases, inputMins, inputMaxes, means, ranges,
                  nnetFile)
    else:
        print("Could not find the given input in graph: %s" % inputOp.name)
Example #8
0
def onnx2nnet(onnxFile,
              inputMins=None,
              inputMaxes=None,
              means=None,
              ranges=None,
              nnetFile="",
              inputName="",
              outputName=""):
    '''
    Write a .nnet file from an onnx file
    Args:
        onnxFile: (string) Path to onnx file
        inputMins: (list) optional, Minimum values for each neural network input.
        inputMaxes: (list) optional, Maximum values for each neural network output.
        means: (list) optional, Mean value for each input and value for mean of all outputs, used for normalization
        ranges: (list) optional, Range value for each input and value for range of all outputs, used for normalization
        inputName: (string) optional, Name of operation corresponding to input.
        outputName: (string) optional, Name of operation corresponding to output.
    '''

    if nnetFile == "":
        nnetFile = onnxFile[:-4] + 'nnet'

    model = onnx.load(onnxFile)
    graph = model.graph

    if not inputName:
        assert len(graph.input) == 1
        inputName = graph.input[0].name
    if not outputName:
        assert len(graph.output) == 1
        outputName = graph.output[0].name

    # Search through nodes until we find the inputName.
    # Accumulate the weight matrices and bias vectors into lists.
    # Continue through the network until we reach outputName.
    # This assumes that the network is "frozen", and the model uses initializers to set weight and bias array values.
    weights = []
    biases = []

    # Loop through nodes in graph
    for node in graph.node:

        # Ignore nodes that do not use inputName as an input to the node
        if inputName in node.input:

            # This supports three types of nodes: MatMul, Add, and Relu
            # The .nnet file format specifies only feedforward fully-connected Relu networks, so
            # these operations are sufficient to specify nnet networks. If the onnx model uses other
            # operations, this will break.
            if node.op_type == "MatMul":
                assert len(node.input) == 2

                # Find the name of the weight matrix, which should be the other input to the node
                weightIndex = 0
                if node.input[0] == inputName:
                    weightIndex = 1
                weightName = node.input[weightIndex]

                # Extract the value of the weight matrix from the initializers
                weights += [
                    numpy_helper.to_array(inits).T
                    for inits in graph.initializer if inits.name == weightName
                ]

                # Update inputName to be the output of this node
                inputName = node.output[0]

            elif node.op_type == "Add":
                assert len(node.input) == 2

                # Find the name of the bias vector, which should be the other input to the node
                biasIndex = 0
                if node.input[0] == inputName:
                    biasIndex = 1
                biasName = node.input[biasIndex]

                # Extract the value of the bias vector from the initializers
                biases += [
                    numpy_helper.to_array(inits) for inits in graph.initializer
                    if inits.name == biasName
                ]

                # Update inputName to be the output of this node
                inputName = node.output[0]

            # For the .nnet file format, the Relu's are implicit, so we just need to update the input
            elif node.op_type == "Relu":
                inputName = node.output[0]

            # If there is a different node in the model that is not supported, through an error and break out of the loop
            else:
                print("Node operation type %s not supported!" % node.op_type)
                weights = []
                biases = []
                break

            # Terminate once we find the outputName in the graph
            if outputName == inputName:
                break

    # Check if the weights and biases were extracted correctly from the graph
    if outputName == inputName and len(weights) > 0 and len(weights) == len(
            biases):

        inputSize = weights[0].shape[0]

        # Default values for input bounds and normalization constants
        if inputMins is None:
            inputMins = inputSize * [np.finfo(np.float32).min]
        if inputMaxes is None:
            inputMaxes = inputSize * [np.finfo(np.float32).max]
        if means is None: means = (inputSize + 1) * [0.0]
        if ranges is None: ranges = (inputSize + 1) * [1.0]

        # Print statements
        print("Converted ONNX model at %s" % onnxFile)
        print("    to an NNet model at %s" % nnetFile)

        # Write NNet file
        writeNNet(weights, biases, inputMins, inputMaxes, means, ranges,
                  nnetFile)

    # Something went wrong, so don't write the NNet file
    else:
        print("Could not write NNet file!")
Example #9
0
def save_nnet(weights, biases, input_mins, input_maxs, means, ranges, output_path):
    # write model in nnet format.
    writeNNet(weights, biases, input_mins, input_maxs, means, ranges, output_path)