def test_q_average_pooling(pooling, input_size, pool_size, strides, padding, data_format, average_quantizer, activation_quantizer, y): """q_average_pooling test utility.""" np.random.seed(33) x = Input(input_size) xin = x if pooling == 'QAveragePooling2D': x = QAveragePooling2D(pool_size=pool_size, strides=strides, padding=padding, data_format=data_format, average_quantizer=average_quantizer, activation=activation_quantizer, name='qpooling')(x) else: x = QGlobalAveragePooling2D(data_format=data_format, average_quantizer=average_quantizer, activation=activation_quantizer, name='qpooling')(x) model = Model(inputs=xin, outputs=x) # Prints qstats to make sure it works with Conv1D layer print_qstats(model) size = (2, ) + input_size inputs = np.random.rand(size[0], size[1], size[2], size[3]) if data_format == 'channels_first': assert_raises(tf.errors.InvalidArgumentError, model.predict, inputs) else: p = model.predict(inputs).astype(np.float16) assert_allclose(p, y, rtol=1e-4) # Reloads the model to ensure saving/loading works json_string = model.to_json() clear_session() reload_model = quantized_model_from_json(json_string) p = reload_model.predict(inputs).astype(np.float16) assert_allclose(p, y, rtol=1e-4) # Saves the model as an h5 file using Keras's model.save() fd, fname = tempfile.mkstemp(".h5") model.save(fname) del model # Delete the existing model # Returns a compiled model identical to the previous one loaded_model = load_qmodel(fname) # Cleans the created h5 file after loading the model os.close(fd) os.remove(fname) # Applys quantizer to weights model_save_quantized_weights(loaded_model) p = loaded_model.predict(inputs).astype(np.float16) assert_allclose(p, y, rtol=1e-4)
def save_model(model_save_name, model): with open(model_save_name + '.json', 'w') as file: file.write(model.to_json()) model.save_weights(model_save_name + '.h5') model_save_quantized_weights( model, model_save_name + '_quantized_weights' + '.h5') model.save(model_save_name + '_h5file.h5')
def test_qbidirectional(rnn, all_weights_signature, expected_output): K.set_learning_phase(0) np.random.seed(22) tf.random.set_seed(22) x = x_in = Input((2, 4), name='input') x = QBidirectional( rnn(16, activation="quantized_po2(8)", kernel_quantizer="quantized_po2(8)", recurrent_quantizer="quantized_po2(8)", bias_quantizer="quantized_po2(8)", name='qbirnn_0'))(x) x = QDense(4, kernel_quantizer=quantized_bits(8, 2, 1, alpha=1.0), bias_quantizer=quantized_bits(8, 0, 1), name='dense')(x) x = Activation('softmax', name='softmax')(x) model = Model(inputs=[x_in], outputs=[x]) # reload the model to ensure saving/loading works json_string = model.to_json() clear_session() model = quantized_model_from_json(json_string) # Save the model as an h5 file using Keras's model.save() fd, fname = tempfile.mkstemp('.h5') model.save(fname) del model # Delete the existing model # Return a compiled model identical to the previous one model = load_qmodel(fname) # Clean the created h5 file after loading the model os.close(fd) os.remove(fname) # apply quantizer to weights model_save_quantized_weights(model) all_weights = [] for layer in model.layers: for i, weights in enumerate(layer.get_weights()): w = np.sum(weights) all_weights.append(w) all_weights = np.array(all_weights) assert all_weights.size == all_weights_signature.size assert np.all(all_weights == all_weights_signature) # test forward: inputs = 2 * np.random.rand(10, 2, 4) actual_output = model.predict(inputs).astype(np.float16) assert_allclose(actual_output, expected_output, rtol=1e-4)
def qbn_model_inference(): x = x_in = keras.layers.Input((23, 23, 1), name="input") x = QConv2D(4, 2, 23, kernel_quantizer=quantizers.quantized_bits(4, 0, 1, alpha=1.0), bias_quantizer=quantizers.quantized_bits(4, 0, 1, alpha=1.0), use_bias=False, name="qconv2d_1")(x) x = QBatchNormalization(mean_quantizer=quantizers.quantized_bits(6, 0, 1), gamma_quantizer=None, variance_quantizer=None, beta_quantizer=quantizers.quantized_bits(6, 0, 1), inverse_quantizer=quantizers.quantized_bits( 16, 0, 1), scale=False, center=False, gamma_range=8, beta_range=4, name="qbn_2")(x) x = QConv2D(2, 1, 1, kernel_quantizer=quantizers.quantized_bits(3, 0), bias_quantizer=quantizers.quantized_bits(3, 2), name="qconv2d_3")(x) model = keras.Model(inputs=[x_in], outputs=[x]) hw_weight_dict = model_save_quantized_weights(model) return (hw_weight_dict, model)
for i, weights in enumerate(layer.get_weights()): weights = K.eval(layer.get_quantizers()[i](K.constant(weights))) print(" ({: 8.4f} {: 8.4f})".format(np.min(weights), np.max(weights)), end="") print("") p_test = mo.predict(x_test) p_test.tofile("p_test.bin") score = model.evaluate(x_test, y_test, verbose=VERBOSE) print("Test score:", score[0]) print("Test accuracy:", score[1]) all_weights = [] model_save_quantized_weights(model) for layer in model.layers: for w, weights in enumerate(layer.get_weights()): print(layer.name, w) all_weights.append(weights.flatten()) all_weights = np.concatenate(all_weights).astype(np.float32) print(all_weights.size) for layer in model.layers: for w, weight in enumerate(layer.get_weights()): print(layer.name, w, weight.shape) print_qstats(model)
def test_qnetwork(): x = x_in = Input((28, 28, 1), name='input') x = QSeparableConv2D( 32, (2, 2), strides=(2, 2), depthwise_quantizer="binary", pointwise_quantizer=quantized_bits(4, 0, 1), depthwise_activation=quantized_bits(6, 2, 1), bias_quantizer=quantized_bits(4, 0, 1), name='conv2d_0_m')( x) x = QActivation('quantized_relu(6,2,1)', name='act0_m')(x) x = QConv2D( 64, (3, 3), strides=(2, 2), kernel_quantizer="ternary", bias_quantizer=quantized_bits(4, 0, 1), name='conv2d_1_m', activation=quantized_relu(6, 3, 1))( x) x = QConv2D( 64, (2, 2), strides=(2, 2), kernel_quantizer=quantized_bits(6, 2, 1), bias_quantizer=quantized_bits(4, 0, 1), name='conv2d_2_m')( x) x = QActivation('quantized_relu(6,4,1)', name='act2_m')(x) x = Flatten(name='flatten')(x) x = QDense( 10, kernel_quantizer=quantized_bits(6, 2, 1), bias_quantizer=quantized_bits(4, 0, 1), name='dense')( x) x = Activation('softmax', name='softmax')(x) model = Model(inputs=[x_in], outputs=[x]) # reload the model to ensure saving/loading works json_string = model.to_json() clear_session() model = quantized_model_from_json(json_string) # generate same output for weights np.random.seed(42) for layer in model.layers: all_weights = [] for i, weights in enumerate(layer.get_weights()): input_size = np.prod(layer.input.shape.as_list()[1:]) if input_size is None: input_size = 576 * 10 # to avoid learning sizes shape = weights.shape assert input_size > 0, 'input size for {} {}'.format(layer.name, i) # he normal initialization with a scale factor of 2.0 all_weights.append( 10.0 * np.random.normal(0.0, np.sqrt(2.0 / input_size), shape)) if all_weights: layer.set_weights(all_weights) # apply quantizer to weights model_save_quantized_weights(model) all_weights = [] for layer in model.layers: for i, weights in enumerate(layer.get_weights()): w = np.sum(weights) all_weights.append(w) all_weights = np.array(all_weights) # test_qnetwork_weight_quantization all_weights_signature = np.array( [2., -6.75, -0.625, -2., -0.25, -56., 1.125, -1.625, -1.125]) assert all_weights.size == all_weights_signature.size assert np.all(all_weights == all_weights_signature) # test_qnetwork_forward: expected_output = np.array([[0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 6.e-08, 1.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00 ,0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 5.e-07, 1.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00 ,1.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00 ,0.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00], [0.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00, 1.e+00, 0.e+00, 0.e+00, 0.e+00, 0.e+00]]).astype(np.float16) inputs = 2 * np.random.rand(10, 28, 28, 1) actual_output = model.predict(inputs).astype(np.float16) assert_allclose(actual_output, expected_output, rtol=1e-4)
def test_qconv1d(): np.random.seed(33) x = Input((4, 4,)) y = QConv1D( 2, 1, kernel_quantizer=quantized_bits(6, 2, 1), bias_quantizer=quantized_bits(4, 0, 1), name='qconv1d')( x) model = Model(inputs=x, outputs=y) #Extract model operations model_ops = extract_model_operations(model) # Assertion about the number of operations for this Conv1D layer assert model_ops['qconv1d']["number_of_operations"] == 32 # Print qstats to make sure it works with Conv1D layer print_qstats(model) # reload the model to ensure saving/loading works json_string = model.to_json() clear_session() model = quantized_model_from_json(json_string) for layer in model.layers: all_weights = [] for i, weights in enumerate(layer.get_weights()): input_size = np.prod(layer.input.shape.as_list()[1:]) if input_size is None: input_size = 10 * 10 shape = weights.shape assert input_size > 0, 'input size for {} {}'.format(layer.name, i) all_weights.append( 10.0 * np.random.normal(0.0, np.sqrt(2.0 / input_size), shape)) if all_weights: layer.set_weights(all_weights) # Save the model as an h5 file using Keras's model.save() fd, fname = tempfile.mkstemp('.h5') model.save(fname) del model # Delete the existing model # Returns a compiled model identical to the previous one model = load_qmodel(fname) #Clean the created h5 file after loading the model os.close(fd) os.remove(fname) # apply quantizer to weights model_save_quantized_weights(model) inputs = np.random.rand(2, 4, 4) p = model.predict(inputs).astype(np.float16) ''' y = np.array([[[0.1309, -1.229], [-0.4165, -2.639], [-0.08105, -2.299], [1.981, -2.195]], [[-0.3174, -3.94], [-0.3352, -2.316], [0.105, -0.833], [0.2115, -2.89]]]).astype(np.float16) ''' y = np.array([[[-2.441, 3.816], [-3.807, -1.426], [-2.684, -1.317], [-1.659, 0.9834]], [[-4.99, 1.139], [-2.559, -1.216], [-2.285, 1.905], [-2.652, -0.467]]]).astype(np.float16) assert np.all(p == y)
def test_qconv1d(layer_cls): np.random.seed(33) if layer_cls == "QConv1D": x = Input(( 4, 4, )) y = QConv1D(2, 1, kernel_quantizer=quantized_bits(6, 2, 1, alpha=1.0), bias_quantizer=quantized_bits(4, 0, 1), name='qconv1d')(x) model = Model(inputs=x, outputs=y) else: x = Input(( 4, 4, )) y = QSeparableConv1D(2, 2, depthwise_quantizer=quantized_bits(6, 2, 1, alpha=1.0), pointwise_quantizer=quantized_bits(4, 0, 1, alpha=1.0), bias_quantizer=quantized_bits(4, 0, 1), name='qconv1d')(x) model = Model(inputs=x, outputs=y) # Extract model operations model_ops = extract_model_operations(model) # Check the input layer model operation was found correctly assert model_ops['qconv1d']['type'][0] != 'null' # Assertion about the number of operations for this (Separable)Conv1D layer if layer_cls == "QConv1D": assert model_ops['qconv1d']['number_of_operations'] == 32 else: assert model_ops['qconv1d']['number_of_operations'] == 30 # Print qstats to make sure it works with Conv1D layer print_qstats(model) # reload the model to ensure saving/loading works # json_string = model.to_json() # clear_session() # model = quantized_model_from_json(json_string) for layer in model.layers: all_weights = [] for i, weights in enumerate(layer.get_weights()): input_size = np.prod(layer.input.shape.as_list()[1:]) if input_size is None: input_size = 10 * 10 shape = weights.shape assert input_size > 0, 'input size for {} {}'.format(layer.name, i) all_weights.append( 10.0 * np.random.normal(0.0, np.sqrt(2.0 / input_size), shape)) if all_weights: layer.set_weights(all_weights) # Save the model as an h5 file using Keras's model.save() fd, fname = tempfile.mkstemp('.h5') model.save(fname) del model # Delete the existing model # Return a compiled model identical to the previous one model = load_qmodel(fname) # Clean the created h5 file after loading the model os.close(fd) os.remove(fname) # apply quantizer to weights model_save_quantized_weights(model) inputs = np.random.rand(2, 4, 4) p = model.predict(inputs).astype(np.float16) if layer_cls == "QConv1D": y = np.array([[[-2.441, 3.816], [-3.807, -1.426], [-2.684, -1.317], [-1.659, 0.9834]], [[-4.99, 1.139], [-2.559, -1.216], [-2.285, 1.905], [-2.652, -0.467]]]).astype(np.float16) else: y = np.array([[[-2.275, -3.178], [-0.4358, -3.262], [1.987, 0.3987]], [[-0.01251, -0.376], [0.3928, -1.328], [-1.243, -2.43]]]).astype(np.float16) assert_allclose(p, y, rtol=1e-4)
def SaveQuantizedWeights(qmodel, qmodelfile): model_save_quantized_weights(qmodel, qmodelfile) return