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 load_model_quantized(model_name): json_file = open(model_name + '.json', 'r') loaded_model_json = json_file.read() json_file.close() model = quantized_model_from_json(loaded_model_json) model.load_weights(model_name + '.h5') return model
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 test_loading(): """Test to load model using different approahches.""" loss_fn = tf.keras.losses.MeanSquaredError() loss_metric = metrics.Mean() optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3) x_shape = (2, 2, 1) custom_objects = {} qkeras_utils._add_supported_quantized_objects(custom_objects) train_ds = generate_dataset(train_size=1, batch_size=1, input_shape=x_shape, num_class=2) model_fold = get_qconv2d_batchnorm_model(input_shape=x_shape, kernel_size=(2, 2), folding_mode="ema_stats_folding") model_fold.compile(loss=loss_fn, optimizer=optimizer, metrics="acc") run_training(model_fold, 10, loss_fn, loss_metric, optimizer, train_ds, do_print=False) # test load model from json to ensure saving/loading model architecture works json_string = model_fold.to_json() clear_session() model_from_json = qkeras_utils.quantized_model_from_json(json_string) assert json_string == model_from_json.to_json() # test reload model from hdf5 files to ensure saving/loading works _, fname = tempfile.mkstemp(".h5") model_fold.save(fname) model_loaded = qkeras_utils.load_qmodel(fname) weight1 = model_fold.layers[1].get_folded_quantized_weight() weight2 = model_loaded.layers[1].get_folded_quantized_weight() assert_equal(weight1[0], weight2[0]) assert_equal(weight1[1], weight2[1]) # test convert a folded model to a normal model for zpm # the kernel/bias weight in the normal model should be the same as the folded # kernel/bias in the folded model normal_model = bn_folding_utils.convert_folded_model_to_normal(model_fold) weight2 = normal_model.layers[1].get_weights() assert_equal(weight1[0], weight2[0]) assert_equal(weight1[1], weight2[1])
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)