From 592fa65aafb61701594a1418c94020b69b83366a Mon Sep 17 00:00:00 2001 From: Chelsea Sidrane Date: Mon, 4 Feb 2019 00:18:48 -0800 Subject: [PATCH 1/2] made parsing more thorough and broke up into smaller functions with more access points --- scripts/pb2nnet.py | 52 +++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/scripts/pb2nnet.py b/scripts/pb2nnet.py index 958c81b..5384ad3 100644 --- a/scripts/pb2nnet.py +++ b/scripts/pb2nnet.py @@ -4,7 +4,7 @@ import os os.environ["CUDA_VISIBLE_DEVICES"] = "-1" import tensorflow as tf -from writeNNet import writeNNet +from NNet.scripts.writeNNet import writeNNet def processGraph(op,input_op, foundInputFlag, weights, biases): ''' @@ -21,7 +21,7 @@ def processGraph(op,input_op, foundInputFlag, weights, biases): (bool): Updated foundInputFlag ''' - if op.node_def.op=='Const': + if op.node_def.op=='Const' and op.outputs[0].consumers()[0].type == 'Identity' : # If constant, extract values and add to weight or bias list depending on shape param = tensor_util.MakeNdarray(op.node_def.attr['value'].tensor) if len(param.shape)>1: @@ -40,9 +40,8 @@ def processGraph(op,input_op, foundInputFlag, weights, biases): else: foundInputFlag = True return foundInputFlag - -def pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, nnetFile="", inputName="", outputName="", savedModel=False, savedModelTags=[]): +def pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, order, nnetFile="", inputName="", outputName="", savedModel=False, savedModelTags=[]): ''' Constructs a MarabouNetworkTF object from a frozen Tensorflow protobuf or SavedModel @@ -63,6 +62,11 @@ def pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, nnetFile="", inputName if nnetFile=="": nnetFile = pbFile[:-2] + 'nnet' + sess = pb2sess(pbFile,inputName="", outputName="", savedModel=False, savedModelTags=[]) + + FFTF2nnet(sess, inputMins, inputMaxes, means, ranges, order, nnetFile, inputName, outputName) + +def pb2sess(pbFile,inputName="", outputName="", savedModel=False, savedModelTags=[]): if savedModel: ### Read SavedModel ### sess = tf.Session() @@ -84,7 +88,14 @@ def pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, nnetFile="", inputName tf.import_graph_def(graph_def, name="") sess = tf.Session(graph=graph) ### END reading protobuf ### + return sess + +def FFTF2nnet(sess, inputMins, inputMaxes, means, ranges, order, nnetFile="", inputName="", outputName=""): + import pdb; pdb.set_trace() + weights, biases = FFTF2W(sess, inputName, outputName) + writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,order, nnetFile) +def FFTF2W(sess, inputName="", outputName=""): ### Find operations corresponding to input and output ### if inputName: inputOp = sess.graph.get_operation_by_name(inputName) @@ -106,21 +117,28 @@ def pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, nnetFile="", inputName foundInputFlag = False foundInputFlag = processGraph(outputOp, inputOp, foundInputFlag, weights, biases) if foundInputFlag: - writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,nnetFile) + return weights, biases else: print("Could not find the given input in graph: %s"%inputOp.name) - -## 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 -pbFile = '../nnet/TestNetwork2.pb' +def pb2W(pbFile, inputName="", outputName="", savedModel=False, savedModelTags=[]): + sess = pb2sess(pbFile,inputName, outputName, savedModel, savedModelTags) + weights, biases = FFTF2W(sess, inputName, outputName) + return weights, biases + +def test(): + ## 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 + pbFile = '../nnet/TestNetwork.pb' -# Convert the file -pb2nnet(pbFile, inputMins, inputMaxes, means, ranges) + # Convert the file + pb2nnet(pbFile, inputMins, inputMaxes, means, ranges, order="xW") From 09a3ac4af1751632c497c8cf6ed69d2ab0d96be2 Mon Sep 17 00:00:00 2001 From: Chelsea Sidrane Date: Mon, 4 Feb 2019 00:19:32 -0800 Subject: [PATCH 2/2] added support for weights of different conventions --- scripts/writeNNet.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/scripts/writeNNet.py b/scripts/writeNNet.py index 10c1259..c8ca6da 100644 --- a/scripts/writeNNet.py +++ b/scripts/writeNNet.py @@ -1,6 +1,6 @@ import numpy as np -def writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,fileName): +def writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,order,fileName): ''' Write network data to the .nnet file format @@ -40,7 +40,12 @@ def writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,fileName): #Extract the necessary information and write the header information numLayers = len(weights) - inputSize = weights[0].shape[0] + if order == 'xW': + inputSize = weights[0].shape[0] + elif order == 'Wx': + inputSize = weights[0].shape[1] + else: + raise NotImplementedError outputSize = len(biases[-1]) maxLayerSize = inputSize @@ -70,11 +75,24 @@ def writeNNet(weights,biases,inputMins,inputMaxes,means,ranges,fileName): # The pattern is repeated by next writing the weights from the first hidden layer to the second hidden layer, # followed by the biases of the second hidden layer. ################## - for w,b in zip(weights,biases): - for j in range(w.shape[1]): + if order == 'xW': + for w,b in zip(weights,biases): + for j in range(w.shape[1]): + for i in range(w.shape[0]): + f2.write("%.5e," % w[i][j]) #Five digits written. More can be used, but that requires more more space. + f2.write("\n") + + for i in range(len(b)): + f2.write("%.5e,\n" % b[i]) #Five digits written. More can be used, but that requires more more space. + elif order == 'Wx': + for w,b in zip(weights,biases): for i in range(w.shape[0]): - f2.write("%.5e," % w[i][j]) #Five digits written. More can be used, but that requires more more space. - f2.write("\n") - - for i in range(len(b)): - f2.write("%.5e,\n" % b[i]) #Five digits written. More can be used, but that requires more more space. + for j in range(w.shape[1]): + f2.write("%.5e," % w[i][j]) + f2.write("\n") + for i in range(len(b)): + f2.write("%.5e,\n" % b[i]) + else: + raise NotImplementedError + +