From 4e76bbab75196998c96887618357d5041e42530f Mon Sep 17 00:00:00 2001 From: mycprotein Date: Thu, 1 Sep 2022 15:18:47 +0800 Subject: [PATCH 1/8] Nano: Add tensorflow quantization example. --- .../tutorial/inference/tensorflow/mnist.py | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 python/nano/tutorial/inference/tensorflow/mnist.py diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/mnist.py new file mode 100644 index 00000000000..ee9eecce6a6 --- /dev/null +++ b/python/nano/tutorial/inference/tensorflow/mnist.py @@ -0,0 +1,121 @@ +# +# Copyright 2016 The BigDL Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is adapted from Keras Tutorial. +# https://github.com/keras-team/keras-io/blob/ +# master/examples/vision/mnist_convnet.py + +# Copyright 2015 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +import numpy as np +import tensorflow as tf +from tensorflow import keras +from keras import layers +from keras import losses, metrics + +from bigdl.nano.tf.keras import Model + +# Model / data parameters +num_classes = 10 +input_shape = (28, 28, 1) + +# Load the data and split it between train and test sets +(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() + +# Scale images to the [0, 1] range +x_train = x_train.astype("float32") / 255 +x_test = x_test.astype("float32") / 255 +# Make sure images have shape (28, 28, 1) +x_train = np.expand_dims(x_train, -1) +x_test = np.expand_dims(x_test, -1) +print("x_train shape:", x_train.shape) +print(x_train.shape[0], "train samples") +print(x_test.shape[0], "test samples") + + +# convert class vectors to binary class matrices +y_train = keras.utils.to_categorical(y_train, num_classes) +y_test = keras.utils.to_categorical(y_test, num_classes) + +model = keras.Sequential( + [ + keras.Input(shape=input_shape), + layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), + layers.MaxPooling2D(pool_size=(2, 2)), + layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), + layers.MaxPooling2D(pool_size=(2, 2)), + layers.Flatten(), + layers.Dropout(0.5), + layers.Dense(num_classes, activation="softmax"), + ] +) + +model = Model(inputs=model.inputs, outputs=model.outputs) + +model.summary() + +batch_size = 128 +epochs = 15 + +model.compile(loss="categorical_crossentropy", + optimizer="adam", metrics=["accuracy"]) + +model.fit(x_train, y_train, batch_size=batch_size, + epochs=epochs, validation_split=0.1) + +score = model.evaluate(x_test, y_test, verbose=0) +print("Test loss:", score[0]) +print("Test accuracy:", score[1]) + + +# Quantization using Intel Neural Compressor +# pip install 'neural-compressor' + +# calib_dataset only accept tf.data.Dataset object +tune_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) + +# Execute quantization +q_model = model.quantize(precision='int8', + accelerator=None, + calib_dataset=tune_dataset, + accuracy_criterion={ + 'relative': 0.01, 'higher_is_better': True}, + approach='static', + tuning_strategy='bayesian', + timeout=0, + max_trials=10, + ) + +y_test_hat = q_model(x_test) +loss = float(tf.reduce_mean( + losses.categorical_crossentropy(y_test, y_test_hat))) +categorical_accuracy = metrics.CategoricalAccuracy() +categorical_accuracy.update_state(y_test, y_test_hat) +accuracy = categorical_accuracy.result().numpy() +print("Quantization test loss:", loss) +print("Quantization test accuracy:", accuracy) From ad515c327908fa6c374ca5302d71efcb1eda1b27 Mon Sep 17 00:00:00 2001 From: mycprotein Date: Fri, 2 Sep 2022 13:04:02 +0800 Subject: [PATCH 2/8] simplify quantize arguments --- .../nano/tutorial/inference/tensorflow/mnist.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/mnist.py index ee9eecce6a6..380d8630198 100644 --- a/python/nano/tutorial/inference/tensorflow/mnist.py +++ b/python/nano/tutorial/inference/tensorflow/mnist.py @@ -100,16 +100,7 @@ tune_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) # Execute quantization -q_model = model.quantize(precision='int8', - accelerator=None, - calib_dataset=tune_dataset, - accuracy_criterion={ - 'relative': 0.01, 'higher_is_better': True}, - approach='static', - tuning_strategy='bayesian', - timeout=0, - max_trials=10, - ) +q_model = model.quantize(calib_dataset=tune_dataset) y_test_hat = q_model(x_test) loss = float(tf.reduce_mean( @@ -119,3 +110,8 @@ accuracy = categorical_accuracy.result().numpy() print("Quantization test loss:", loss) print("Quantization test accuracy:", accuracy) +# Raw model test loss: 0.024767747148871422 +# Raw model test accuracy: 0.9918000102043152 +# Quantized model test loss: 0.02494174614548683 +# Quantized model test accuracy: 0.9917 +# Accuracy loss: 0.01% From 2d28961c1e2f24134eba699cfe2ba4e66f9c79b0 Mon Sep 17 00:00:00 2001 From: mycprotein Date: Tue, 6 Sep 2022 10:50:50 +0800 Subject: [PATCH 3/8] add some extra comments --- python/nano/tutorial/inference/tensorflow/mnist.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/mnist.py index 380d8630198..bce0b57861c 100644 --- a/python/nano/tutorial/inference/tensorflow/mnist.py +++ b/python/nano/tutorial/inference/tensorflow/mnist.py @@ -38,6 +38,7 @@ from keras import layers from keras import losses, metrics +# keras.Model is injected with customized functions from bigdl.nano.tf.keras import Model # Model / data parameters @@ -75,7 +76,8 @@ ] ) -model = Model(inputs=model.inputs, outputs=model.outputs) +# this line is optional +# model = Model(inputs=model.inputs, outputs=model.outputs) model.summary() @@ -102,16 +104,22 @@ # Execute quantization q_model = model.quantize(calib_dataset=tune_dataset) +# Inference using quantized model y_test_hat = q_model(x_test) + +# Evaluate the quantized model loss = float(tf.reduce_mean( losses.categorical_crossentropy(y_test, y_test_hat))) categorical_accuracy = metrics.CategoricalAccuracy() categorical_accuracy.update_state(y_test, y_test_hat) accuracy = categorical_accuracy.result().numpy() + print("Quantization test loss:", loss) print("Quantization test accuracy:", accuracy) # Raw model test loss: 0.024767747148871422 # Raw model test accuracy: 0.9918000102043152 # Quantized model test loss: 0.02494174614548683 # Quantized model test accuracy: 0.9917 -# Accuracy loss: 0.01% +# Accuracy loss: about 0.1% in this case +# Note: accuracy loss varies from different tasks and situations, +# but you can set a quantization threshold when making a quantization model. From d2ff0978ca71dced698971af755f4634e478c67f Mon Sep 17 00:00:00 2001 From: mycprotein Date: Tue, 6 Sep 2022 14:44:57 +0800 Subject: [PATCH 4/8] delete concrete numbers --- python/nano/tutorial/inference/tensorflow/mnist.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/mnist.py index bce0b57861c..29e6a890666 100644 --- a/python/nano/tutorial/inference/tensorflow/mnist.py +++ b/python/nano/tutorial/inference/tensorflow/mnist.py @@ -116,10 +116,6 @@ print("Quantization test loss:", loss) print("Quantization test accuracy:", accuracy) -# Raw model test loss: 0.024767747148871422 -# Raw model test accuracy: 0.9918000102043152 -# Quantized model test loss: 0.02494174614548683 -# Quantized model test accuracy: 0.9917 # Accuracy loss: about 0.1% in this case # Note: accuracy loss varies from different tasks and situations, # but you can set a quantization threshold when making a quantization model. From fbc0470ecfe37998c29f49b9e5dc2cb3232572e0 Mon Sep 17 00:00:00 2001 From: mycprotein Date: Thu, 8 Sep 2022 16:18:46 +0800 Subject: [PATCH 5/8] change dataset to cifar10 --- .../tutorial/inference/tensorflow/mnist.py | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/mnist.py index 29e6a890666..9a106dc1c32 100644 --- a/python/nano/tutorial/inference/tensorflow/mnist.py +++ b/python/nano/tutorial/inference/tensorflow/mnist.py @@ -43,17 +43,14 @@ # Model / data parameters num_classes = 10 -input_shape = (28, 28, 1) +input_shape = (32, 32, 3) # Load the data and split it between train and test sets -(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() +(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data() # Scale images to the [0, 1] range x_train = x_train.astype("float32") / 255 x_test = x_test.astype("float32") / 255 -# Make sure images have shape (28, 28, 1) -x_train = np.expand_dims(x_train, -1) -x_test = np.expand_dims(x_test, -1) print("x_train shape:", x_train.shape) print(x_train.shape[0], "train samples") print(x_test.shape[0], "test samples") @@ -63,18 +60,34 @@ y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) -model = keras.Sequential( - [ - keras.Input(shape=input_shape), - layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), - layers.MaxPooling2D(pool_size=(2, 2)), - layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), - layers.MaxPooling2D(pool_size=(2, 2)), - layers.Flatten(), - layers.Dropout(0.5), - layers.Dense(num_classes, activation="softmax"), - ] -) +model = keras.Sequential() + +model.add(layers.Conv2D(32, (3,3), padding='same', activation='relu', input_shape=(32,32,3))) +model.add(layers.BatchNormalization()) +model.add(layers.Conv2D(32, (3,3), padding='same', activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.MaxPooling2D(pool_size=(2,2))) +model.add(layers.Dropout(0.3)) + +model.add(layers.Conv2D(64, (3,3), padding='same', activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.Conv2D(64, (3,3), padding='same', activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.MaxPooling2D(pool_size=(2,2))) +model.add(layers.Dropout(0.5)) + +model.add(layers.Conv2D(128, (3,3), padding='same', activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.Conv2D(128, (3,3), padding='same', activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.MaxPooling2D(pool_size=(2,2))) +model.add(layers.Dropout(0.5)) + +model.add(layers.Flatten()) +model.add(layers.Dense(128, activation='relu')) +model.add(layers.BatchNormalization()) +model.add(layers.Dropout(0.5)) +model.add(layers.Dense(num_classes, activation='softmax')) # this line is optional # model = Model(inputs=model.inputs, outputs=model.outputs) @@ -82,7 +95,7 @@ model.summary() batch_size = 128 -epochs = 15 +epochs = 20 model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) @@ -116,6 +129,6 @@ print("Quantization test loss:", loss) print("Quantization test accuracy:", accuracy) -# Accuracy loss: about 0.1% in this case -# Note: accuracy loss varies from different tasks and situations, -# but you can set a quantization threshold when making a quantization model. +# Note: accuracy decrease varies from different tasks and situations, +# and sometimes the accuracy is even higher. +# You can set a quantization threshold when making a quantization model. \ No newline at end of file From 9f592bbc9f05a54aaedaadb17c93ae0ba32d649e Mon Sep 17 00:00:00 2001 From: mycprotein Date: Fri, 9 Sep 2022 15:16:49 +0800 Subject: [PATCH 6/8] change file name to cifar10 --- .../nano/tutorial/inference/tensorflow/{mnist.py => cifar10.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/nano/tutorial/inference/tensorflow/{mnist.py => cifar10.py} (100%) diff --git a/python/nano/tutorial/inference/tensorflow/mnist.py b/python/nano/tutorial/inference/tensorflow/cifar10.py similarity index 100% rename from python/nano/tutorial/inference/tensorflow/mnist.py rename to python/nano/tutorial/inference/tensorflow/cifar10.py From b703a6f7d4c44bfc03e197a9e302e1026b442dce Mon Sep 17 00:00:00 2001 From: mycprotein Date: Tue, 13 Sep 2022 10:20:52 +0800 Subject: [PATCH 7/8] improve code organization --- .../tutorial/inference/tensorflow/cifar10.py | 152 +++++++++--------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/cifar10.py b/python/nano/tutorial/inference/tensorflow/cifar10.py index 9a106dc1c32..57fdab57e7a 100644 --- a/python/nano/tutorial/inference/tensorflow/cifar10.py +++ b/python/nano/tutorial/inference/tensorflow/cifar10.py @@ -60,75 +60,83 @@ y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) -model = keras.Sequential() - -model.add(layers.Conv2D(32, (3,3), padding='same', activation='relu', input_shape=(32,32,3))) -model.add(layers.BatchNormalization()) -model.add(layers.Conv2D(32, (3,3), padding='same', activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.MaxPooling2D(pool_size=(2,2))) -model.add(layers.Dropout(0.3)) - -model.add(layers.Conv2D(64, (3,3), padding='same', activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.Conv2D(64, (3,3), padding='same', activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.MaxPooling2D(pool_size=(2,2))) -model.add(layers.Dropout(0.5)) - -model.add(layers.Conv2D(128, (3,3), padding='same', activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.Conv2D(128, (3,3), padding='same', activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.MaxPooling2D(pool_size=(2,2))) -model.add(layers.Dropout(0.5)) - -model.add(layers.Flatten()) -model.add(layers.Dense(128, activation='relu')) -model.add(layers.BatchNormalization()) -model.add(layers.Dropout(0.5)) -model.add(layers.Dense(num_classes, activation='softmax')) - -# this line is optional -# model = Model(inputs=model.inputs, outputs=model.outputs) - -model.summary() - -batch_size = 128 -epochs = 20 - -model.compile(loss="categorical_crossentropy", - optimizer="adam", metrics=["accuracy"]) - -model.fit(x_train, y_train, batch_size=batch_size, - epochs=epochs, validation_split=0.1) - -score = model.evaluate(x_test, y_test, verbose=0) -print("Test loss:", score[0]) -print("Test accuracy:", score[1]) - - -# Quantization using Intel Neural Compressor -# pip install 'neural-compressor' - -# calib_dataset only accept tf.data.Dataset object -tune_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) - -# Execute quantization -q_model = model.quantize(calib_dataset=tune_dataset) - -# Inference using quantized model -y_test_hat = q_model(x_test) - -# Evaluate the quantized model -loss = float(tf.reduce_mean( - losses.categorical_crossentropy(y_test, y_test_hat))) -categorical_accuracy = metrics.CategoricalAccuracy() -categorical_accuracy.update_state(y_test, y_test_hat) -accuracy = categorical_accuracy.result().numpy() - -print("Quantization test loss:", loss) -print("Quantization test accuracy:", accuracy) -# Note: accuracy decrease varies from different tasks and situations, -# and sometimes the accuracy is even higher. -# You can set a quantization threshold when making a quantization model. \ No newline at end of file + +def creat_model(): + model = keras.Sequential() + + model.add(layers.Conv2D(32, (3, 3), padding='same', + activation='relu', input_shape=(32, 32, 3))) + model.add(layers.BatchNormalization()) + model.add(layers.Conv2D(32, (3, 3), padding='same', activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.MaxPooling2D(pool_size=(2, 2))) + model.add(layers.Dropout(0.3)) + + model.add(layers.Conv2D(64, (3, 3), padding='same', activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.Conv2D(64, (3, 3), padding='same', activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.MaxPooling2D(pool_size=(2, 2))) + model.add(layers.Dropout(0.5)) + + model.add(layers.Conv2D(128, (3, 3), padding='same', activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.Conv2D(128, (3, 3), padding='same', activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.MaxPooling2D(pool_size=(2, 2))) + model.add(layers.Dropout(0.5)) + + model.add(layers.Flatten()) + model.add(layers.Dense(128, activation='relu')) + model.add(layers.BatchNormalization()) + model.add(layers.Dropout(0.5)) + model.add(layers.Dense(num_classes, activation='softmax')) + return model + + +if __name__ == "__main__": + + model = creat_model() + + # this line is optional + # model = Model(inputs=model.inputs, outputs=model.outputs) + + model.summary() + + batch_size = 128 + epochs = 20 + + model.compile(loss="categorical_crossentropy", + optimizer="adam", metrics=["accuracy"]) + + model.fit(x_train, y_train, batch_size=batch_size, + epochs=epochs, validation_split=0.1) + + score = model.evaluate(x_test, y_test, verbose=0) + print("Test loss:", score[0]) + print("Test accuracy:", score[1]) + + # Quantization using Intel Neural Compressor + # pip install 'neural-compressor' + + # calib_dataset only accept tf.data.Dataset object + tune_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) + + # Execute quantization + q_model = model.quantize(calib_dataset=tune_dataset) + + # Inference using quantized model + y_test_hat = q_model(x_test) + + # Evaluate the quantized model + loss = float(tf.reduce_mean( + losses.categorical_crossentropy(y_test, y_test_hat))) + categorical_accuracy = metrics.CategoricalAccuracy() + categorical_accuracy.update_state(y_test, y_test_hat) + accuracy = categorical_accuracy.result().numpy() + + print("Quantization test loss:", loss) + print("Quantization test accuracy:", accuracy) + # Note: accuracy decrease varies from different tasks and situations, + # and sometimes the accuracy is even higher. + # You can set a quantization threshold when making a quantization model. From 6c307f5e081e5e06990e032b32b7a9377c20e7de Mon Sep 17 00:00:00 2001 From: mycprotein Date: Thu, 15 Sep 2022 11:53:06 +0800 Subject: [PATCH 8/8] remove unnecessary comments --- .../tutorial/inference/tensorflow/cifar10.py | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/python/nano/tutorial/inference/tensorflow/cifar10.py b/python/nano/tutorial/inference/tensorflow/cifar10.py index 57fdab57e7a..80e3850b254 100644 --- a/python/nano/tutorial/inference/tensorflow/cifar10.py +++ b/python/nano/tutorial/inference/tensorflow/cifar10.py @@ -12,27 +12,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -# This file is adapted from Keras Tutorial. -# https://github.com/keras-team/keras-io/blob/ -# master/examples/vision/mnist_convnet.py - -# Copyright 2015 The TensorFlow Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================== -import numpy as np + import tensorflow as tf from tensorflow import keras from keras import layers