import os
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
import tensorflow as tf
from imblearn.over_sampling import SMOTE
from tensorflow.keras.layers import Input,Dense
from tensorflow.keras.models import Model
from tensorflow.keras import optimizers
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
warnings.filterwarnings('ignore')
print("Version TF " + tf.__version__ + " > 2.11 pour fonctionner avec TFLite")
Version TF 2.17.0 > 2.11 pour fonctionner avec TFLite
Dans ce TP, vous apprendrez à construire un modèle prêt à être déployé sur un appareil embarqué grâce à TensorFlow Lite (TFLite). A la fin de ce laboratoire, vous aurez une bonne compréhension de la façon de créer des modèles de petite taille à travers la quantification.
1 Creation du modèle¶
X = pd.read_csv('/X.csv', header=None)
y = pd.read_csv('/y.csv', header=None)
Inspecter et comprendre les données¶
# Vérifier les dimensions des données
print("Dimensions de X:", X.shape)
print("Dimensions de y:", y.shape)
print("*****************************************************************************")
print(X.head()) # Affiche les premières lignes des features
print(y.head()) # Affiche les premières lignes des labels
print("*****************************************************************************")
# Résumer les statistiques de base
print(X.describe()) # Statistiques descriptives sur les features
print(y.describe()) # Statistiques descriptives sur les labels
print("*****************************************************************************")
# Vérifier s'il y a des valeurs manquantes
print("Nombre de valeurs manquantes dans X:", np.isnan(X).sum())
print("Nombre de valeurs manquantes dans y:", np.isnan(y).sum())
print("*****************************************************************************")
# Vérifier la distribution des classes dans y
print("Distribution des classes dans y: ", y.value_counts())
Dimensions de X: (2487, 1024)
Dimensions de y: (2487, 1)
****************************************************************************************************
0 1 2 3 4 5 6 \
0 0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000
1 0.147927 -0.044995 0.108069 0.062458 -0.049104 0.170116 0.106836
2 -0.019518 0.141147 0.140942 -0.019313 -0.020545 -0.044789 -0.064513
3 -0.069444 -0.022189 -0.009245 0.000205 0.135189 0.068622 0.132518
4 0.127998 -0.066362 0.053829 -0.005958 -0.051364 0.088551 0.072525
7 8 9 ... 1014 1015 1016 \
0 7.000000 8.000000 9.000000 ... 1014.000000 1015.000000 1016.000000
1 0.005958 0.042735 0.094098 ... 0.138476 0.025682 0.129642
2 -0.018285 0.003287 -0.011505 ... 0.014587 -0.061431 0.136627
3 0.057527 -0.014382 0.009451 ... 0.030613 0.052185 -0.155940
4 0.051569 0.106425 0.095536 ... 0.027120 -0.053418 0.047460
1017 1018 1019 1020 1021 \
0 1017.000000 1018.000000 1019.000000 1020.000000 1021.000000
1 0.079716 -0.032256 0.038215 -0.021984 -0.091838
2 0.113616 0.064307 0.207509 0.074169 0.029175
3 0.034927 0.132518 -0.028558 0.027531 0.129847
4 0.075402 -0.069855 0.030818 -0.057938 -0.168062
1022 1023
0 1022.000000 1023.000000
1 0.046844 0.067389
2 -0.033695 -0.073142
3 0.107247 0.212851
4 0.054445 0.061636
[5 rows x 1024 columns]
0
0 0
1 1
2 1
3 1
4 1
****************************************************************************************************
0 1 2 3 4 \
count 2487.000000 2487.000000 2487.000000 2487.000000 2487.000000
mean 0.030880 0.031755 0.034948 0.031410 0.035558
std 0.134111 0.132239 0.138989 0.142474 0.153790
min -0.986182 -0.730185 -0.749909 -0.762442 -0.686629
25% -0.030613 -0.029791 -0.028455 -0.032462 -0.030202
50% 0.030202 0.029996 0.033695 0.029791 0.030818
75% 0.092865 0.093379 0.095742 0.089373 0.095023
max 0.994811 1.000000 2.000000 3.000000 4.000000
5 6 7 8 9 ... \
count 2487.000000 2487.000000 2487.000000 2487.000000 2487.000000 ...
mean 0.038312 0.032708 0.034094 0.035553 0.037960 ...
std 0.169280 0.181619 0.189089 0.206094 0.223310 ...
min -0.920231 -0.964404 -0.695464 -0.755867 -0.844829 ...
25% -0.028353 -0.032051 -0.032975 -0.030818 -0.030921 ...
50% 0.035133 0.031024 0.030613 0.030202 0.034722 ...
75% 0.098515 0.091016 0.093687 0.092044 0.096255 ...
max 5.000000 6.000000 7.000000 8.000000 9.000000 ...
1014 1015 1016 1017 1018 \
count 2487.000000 2487.000000 2487.000000 2487.000000 2487.000000
mean 0.439092 0.442580 0.441548 0.439457 0.443002
std 20.332704 20.352734 20.372788 20.392908 20.412921
min -0.692998 -1.087265 -0.852842 -1.189787 -0.777029
25% -0.032975 -0.029380 -0.028147 -0.030407 -0.028764
50% 0.029175 0.032256 0.033489 0.029996 0.032667
75% 0.091530 0.091838 0.095742 0.093585 0.091427
max 1014.000000 1015.000000 1016.000000 1017.000000 1018.000000
1019 1020 1021 1022 1023
count 2487.000000 2487.000000 2487.000000 2487.000000 2487.000000
mean 0.445459 0.443702 0.440632 0.439286 0.442693
std 20.432885 20.453010 20.473125 20.493218 20.513222
min -0.665467 -1.383531 -0.919820 -1.480916 -1.007549
25% -0.027325 -0.029483 -0.028147 -0.031845 -0.030099
50% 0.035544 0.031229 0.030818 0.029791 0.032256
75% 0.096255 0.093790 0.090811 0.091427 0.095639
max 1019.000000 1020.000000 1021.000000 1022.000000 1023.000000
[8 rows x 1024 columns]
0
count 2487.000000
mean 3.670688
std 3.538166
min 0.000000
25% 0.000000
50% 3.000000
75% 7.000000
max 9.000000
****************************************************************************************************
Nombre de valeurs manquantes dans X: 0 0
1 0
2 0
3 0
4 0
..
1019 0
1020 0
1021 0
1022 0
1023 0
Length: 1024, dtype: int64
Nombre de valeurs manquantes dans y: 0 0
dtype: int64
****************************************************************************************************
Distribution des classes dans y: 0
0 946
9 357
7 355
2 119
3 119
4 119
1 118
5 118
6 118
8 118
Name: count, dtype: int64
X contient 2487 lignes et 1024 colonnes. Cela ressemble à des données de type vecteur. Chaque ligne semble représenter une instance (avec 1024 caractéristiques), et les valeurs varient entre des nombres négatifs et positifs.
y contient également 2487 lignes et une seule colonne, ce qui correspond bien aux étiquettes associées à chaque ligne de X.
Prétraitement des données & Division des données en jeu d’entraînement et de test¶
Certaines colonnes de X semblent avoir des valeurs très élevées (par exemple, allant jusqu'à 1023). Cela pourrait signifier que certaines données sont mal normalisées, ou que ces valeurs doivent être traitées spécifiquement selon le modèle que tu comptes entraîner. Les premières colonnes semblent avoir des valeurs qui ressemblent davantage à des features standardisées ou normalisées.
Puisque il y a un déséquilibre dans les classes, envisage d'utiliser une stratégie d'échantillonnage, comme le suréchantillonnage (SMOTE)
# 2. Gestion des classes déséquilibrées avec SMOTE
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)
# 3. Séparation des données
X_train, X_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=0.2, random_state=42, stratify=y_resampled)
Normalise des données
# 4. Normalisation
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Vérifier les dimensions des jeux de données
print("Dimensions de X_train:", X_train.shape)
print("Dimensions de X_test:", X_test.shape)
print("Dimensions de y_train:", y_train.shape)
print("Dimensions de y_test:", y_test.shape)
Dimensions de X_train: (7568, 1024) Dimensions de X_test: (1892, 1024) Dimensions de y_train: (7568, 1) Dimensions de y_test: (1892, 1)
Taille de l'échantillon : X_train et y_train contiennent les données d'entraînement, tandis que X_test et y_test contiennent les données de test. Les dimensions indiquées montrent que la taille d'échantillon totale de 7568 pour l'ensemble d'entraînement et 1892 pour l'ensemble de test.
Stratification : La stratification dans la fonction train_test_split garantit que la distribution des classes dans les ensembles d'entraînement et de test est similaire. C'est important pour évaluer correctement les performances du modèle.
Taux de séparation : test_size de 0.2 20% des données sont utilisées pour le test et 80% pour l'entraînement. Avec 9480 exemples au total après le suréchantillonnage, cela correspond à 7568 pour l'entraînement et 1892 pour le test.
Créer et compiler un modèle d’apprendissage profond¶
n = X_train.shape[1] # Nombre de caractéristiques
n_classes = len(np.unique(y_train)) # Nombre de classes
"""
@author: F. PACHECO
"""
# Création du modèle
input_ = Input(shape=(n,)) # Couche d'entrée
x = Dense(50, activation='relu')(input_) # Couche cachée
output_ = Dense(n_classes, activation='softmax')(x) # Couche de sortie
model = Model(input_, output_) # Création du modèle
# Compilation du modèle
opt = optimizers.RMSprop(learning_rate=0.001)
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# Entraînement du modèle
history = model.fit(X_train, y_train, batch_size=32, epochs=20, validation_data=(X_test, y_test), verbose=2)
model.save("original_model.h5")
Epoch 1/20 237/237 - 6s - 23ms/step - accuracy: 1.0000 - loss: 0.0026 - val_accuracy: 0.9820 - val_loss: 0.0782 Epoch 2/20 237/237 - 2s - 8ms/step - accuracy: 1.0000 - loss: 0.0022 - val_accuracy: 0.9841 - val_loss: 0.0763 Epoch 3/20 237/237 - 2s - 9ms/step - accuracy: 1.0000 - loss: 0.0018 - val_accuracy: 0.9836 - val_loss: 0.0789 Epoch 4/20 237/237 - 1s - 4ms/step - accuracy: 1.0000 - loss: 0.0016 - val_accuracy: 0.9831 - val_loss: 0.0803 Epoch 5/20 237/237 - 1s - 4ms/step - accuracy: 1.0000 - loss: 0.0014 - val_accuracy: 0.9831 - val_loss: 0.0821 Epoch 6/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 0.0012 - val_accuracy: 0.9831 - val_loss: 0.0813 Epoch 7/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 0.0011 - val_accuracy: 0.9841 - val_loss: 0.0816 Epoch 8/20 237/237 - 1s - 5ms/step - accuracy: 1.0000 - loss: 9.7691e-04 - val_accuracy: 0.9826 - val_loss: 0.0820 Epoch 9/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 8.8412e-04 - val_accuracy: 0.9831 - val_loss: 0.0830 Epoch 10/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 8.0593e-04 - val_accuracy: 0.9836 - val_loss: 0.0838 Epoch 11/20 237/237 - 1s - 6ms/step - accuracy: 1.0000 - loss: 7.4100e-04 - val_accuracy: 0.9836 - val_loss: 0.0841 Epoch 12/20 237/237 - 2s - 7ms/step - accuracy: 1.0000 - loss: 6.8626e-04 - val_accuracy: 0.9836 - val_loss: 0.0856 Epoch 13/20 237/237 - 1s - 5ms/step - accuracy: 1.0000 - loss: 6.3674e-04 - val_accuracy: 0.9836 - val_loss: 0.0841 Epoch 14/20 237/237 - 1s - 6ms/step - accuracy: 1.0000 - loss: 5.9553e-04 - val_accuracy: 0.9831 - val_loss: 0.0849 Epoch 15/20 237/237 - 2s - 8ms/step - accuracy: 1.0000 - loss: 5.5489e-04 - val_accuracy: 0.9831 - val_loss: 0.0873 Epoch 16/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 5.2157e-04 - val_accuracy: 0.9841 - val_loss: 0.0861 Epoch 17/20 237/237 - 1s - 5ms/step - accuracy: 1.0000 - loss: 4.9238e-04 - val_accuracy: 0.9841 - val_loss: 0.0875 Epoch 18/20 237/237 - 1s - 5ms/step - accuracy: 1.0000 - loss: 4.6452e-04 - val_accuracy: 0.9836 - val_loss: 0.0877 Epoch 19/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 4.3988e-04 - val_accuracy: 0.9831 - val_loss: 0.0864 Epoch 20/20 237/237 - 1s - 3ms/step - accuracy: 1.0000 - loss: 4.1844e-04 - val_accuracy: 0.9826 - val_loss: 0.0889
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
model.summary()
Model: "functional"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ input_layer (InputLayer) │ (None, 1024) │ 0 │ ├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤ │ dense (Dense) │ (None, 50) │ 51,250 │ ├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤ │ dense_1 (Dense) │ (None, 10) │ 510 │ └──────────────────────────────────────┴─────────────────────────────┴─────────────────┘
Total params: 103,522 (404.39 KB)
Trainable params: 51,760 (202.19 KB)
Non-trainable params: 0 (0.00 B)
Optimizer params: 51,762 (202.20 KB)
2 Quantification¶
Afin d’effectuer des comparaisons, obtenir et sauvegarder les modèles suivants :
- Converted Model : Convertir le modèle original en utilisant les options par défaut.
- Model Float16 : Quantifier les poids du modèle en valeurs flottantes de 16 bits.
- Model Int16 : Quantifier les poids du modèle en valeurs entiers de 16 bits.
- Model Int16 8 : Quantifier les poids en valeurs entiers de 8 bits et les activations du modèle en valeurs entiers de 16 bits.
- Model Int8 : Quantifier les poids et les activations du modèle en valeurs entiers de 8 bits.
Pour sauvegarder chaque modèle, veuillez utiliser :
open("converted_model.tflite", "wb").write(tflite_model)
Étapes pour convertir le modèle
- Créer le modèle avec TensorFlow ou charger un modèle enregistré.
- Créer une instance de TFLiteConverter avec le modèle.
- Ajouter les paramètres d'optimisation à l'instance de TFLiteConverter (quantification des poids et des activations).
- Convertir le modèle.
"""
@author: F. PACHECO
"""
# Création instance de tFLiteConverter
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
# Sauvegarder le modèle
open("model_converted.tflite", "wb").write(tflite_model)
Saved artifact at '/tmp/tmpamf9saa2'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None)
208752
"""
@author: F. PACHECO
"""
# Indiquer que nous voulons effectuer les optimisations par défaut
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# --------------------------
# AJOUT DE DONNÉES REPRÉSENTATIVES (pour la quantification des activations)
def representative_dataset_generator():
for value in X_test[:100]: # Limiter le nombre d'exemples pour une estimation rapide
yield [np.array(value, dtype=np.float32, ndmin=2)]
converter.representative_dataset = representative_dataset_generator
# --------------------------
# Convertir le modèle
tflite_model_quantized = converter.convert()
# Sauvegarder le modèle sur le disque
with open("model_quantized.tflite", "wb") as f:
f.write(tflite_model_quantized)
print("Le modèle TFLite quantifié a été créé et sauvegardé avec succès !")
Saved artifact at '/tmp/tmpa3o6sg50'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None) Le modèle TFLite quantifié a été créé et sauvegardé avec succès !
# Quantification des poids en float16
converter_float16 = tf.lite.TFLiteConverter.from_keras_model(model)
converter_float16.optimizations = [tf.lite.Optimize.DEFAULT]
converter_float16.target_spec.supported_types = [tf.float16]
model_float16 = converter_float16.convert()
with open("model_float16.tflite", "wb") as f:
f.write(model_float16)
# Quantification des poids en int16
converter_int16 = tf.lite.TFLiteConverter.from_keras_model(model)
converter_int16.optimizations = [tf.lite.Optimize.DEFAULT]
converter_int16.target_spec.supported_types = [tf.int16]
model_int16 = converter_int16.convert()
with open("model_int16.tflite", "wb") as f:
f.write(model_int16)
# Quantification des poids en int8 et des activations en int16
converter_int16_8 = tf.lite.TFLiteConverter.from_keras_model(model)
converter_int16_8.optimizations = [tf.lite.Optimize.DEFAULT]
converter_int16_8.target_spec.supported_types = [tf.int8]
converter_int16_8.target_spec.supported_types = [tf.int16] # Pour les activations
model_int16_8 = converter_int16_8.convert()
with open("model_int16_8.tflite", "wb") as f:
f.write(model_int16_8)
# Quantification des poids et des activations en int8
converter_int8 = tf.lite.TFLiteConverter.from_keras_model(model)
converter_int8.optimizations = [tf.lite.Optimize.DEFAULT]
# Indiquer que nous voulons effectuer la quantification entière
def representative_dataset_generator():
for value in X_test[:100]: # Limiter le nombre d'exemples pour une estimation rapide
yield [np.array(value, dtype=np.float32, ndmin=2)]
converter_int8.representative_dataset = representative_dataset_generator
model_int8 = converter_int8.convert()
with open("model_int8.tflite", "wb") as f:
f.write(model_int8)
print("Tous les modèles TFLite ont été créés et sauvegardés avec succès !")
Saved artifact at '/tmp/tmpwot79tup'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None) Saved artifact at '/tmp/tmpm6fop06v'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None) Saved artifact at '/tmp/tmpzato43jn'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None) Saved artifact at '/tmp/tmp3ccgqm7u'. The following endpoints are available: * Endpoint 'serve' args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 1024), dtype=tf.float32, name='keras_tensor') Output Type: TensorSpec(shape=(None, 10), dtype=tf.float32, name=None) Captures: 138264081523008: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081822320: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081824960: TensorSpec(shape=(), dtype=tf.resource, name=None) 138264081823904: TensorSpec(shape=(), dtype=tf.resource, name=None) Tous les modèles TFLite ont été créés et sauvegardés avec succès !
3 Comparaison¶
"""
@author: A. Belaich
"""
def evaluate_models(models, X_train, y_train, X_test, y_test):
results = []
for model_name, model_path in models.items():
# Charger le modèle
if model_name == "model_original":
model = tf.keras.models.load_model(model_path)
else:
interpreter = tf.lite.Interpreter(model_path=model_path)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# Évaluer la précision
if model_name == "model_original":
y_pred = model.predict(X_test)
y_pred_classes = np.argmax(y_pred, axis=1)
else:
# Évaluation du modèle TFLite
y_pred_classes = []
for sample in X_test:
interpreter.set_tensor(input_details[0]['index'], sample.reshape(1, -1).astype(np.float32))
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
y_pred_classes.append(np.argmax(output_data))
accuracy = accuracy_score(y_test, y_pred_classes)
# Mesurer la taille du modèle
size = os.path.getsize(model_path)
# Mesurer la latence
start_time = time.time()
for sample in X_test[:10]: # Tester sur quelques échantillons pour mesurer la latence
if model_name == "model_original":
model.predict(sample.reshape(1, -1))
else:
interpreter.set_tensor(input_details[0]['index'], sample.reshape(1, -1).astype(np.float32))
interpreter.invoke()
end_time = time.time()
latency = (end_time - start_time) / 10 # Temps moyen par échantillon
# Ajouter les résultats à la liste
results.append({
'model_name': model_name,
'accuracy': accuracy,
'size': size,
'latency': latency
})
# Convertir les résultats en DataFrame pour une analyse facile
results_df = pd.DataFrame(results)
print("Results:\n", results_df)
return results_df
models = {
"model_original": "original_model.h5",
"model_converted": "model_converted.tflite",
"model_float16": "model_float16.tflite",
"model_int16": "model_int16.tflite",
"model_int8": "model_int8.tflite",
"model_int16_8": "model_int16_8.tflite",
}
results_df = evaluate_models(models, X_train, y_train, X_test, y_test)
WARNING:absl:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
60/60 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 103ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 49ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 65ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 107ms/step 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step Results: model_name accuracy size latency 0 model_original 0.982558 434896 0.164625 1 model_converted 0.981501 208752 0.000044 2 model_float16 0.981501 105792 0.000041 3 model_int16 0.981501 208752 0.000045 4 model_int8 0.982030 55704 0.000032 5 model_int16_8 0.981501 208752 0.000044
Basé sur la précision :
Le modèle Int8 a la meilleure précision de 0.982030.
Basé sur la taille :
Le modèle Int8 est aussi le plus léger avec une taille de 55704.
Basé sur la latence :
Le modèle Int8 a également la latence la plus faible de 0.000032.
Conclusion
Le modèle Int8 est le meilleur choix dans tous les critères (précision, taille et latence). Si d'autres critères ou objectifs spécifiques sont pris en compte, cela pourrait affecter le choix, mais selon les résultats fournis, le modèle Int8 est le plus performant.
4 Quantification sur TFLite¶
Quelle technique de quantification (symétrique, asymétrique, etc.) est utilisée pour le modèle int8 dans le tableau précédent ?¶
La quantification utilisée pour le modèle int8 est généralement la quantification asymétrique. Dans ce cas, chaque poids du modèle est quantifié indépendamment à l'aide d'un décalage (offset) et d'un facteur d'échelle (scale).
Mathématiquement, pour un poids w dans le modèle, la quantification asymétrique peut être exprimée comme suit :
q = round((w - zero_point) / scale)
Où q est le poids quantifié, zero_point est la valeur de décalage, et scale est le facteur d'échelle qui ajuste l'intervalle des valeurs flottantes en valeurs entières.
2. Comment les données représentatives sont-elles exploitées par ce quantificateur ?¶
Les données représentatives sont essentielles pour déterminer les valeurs zero_point et scale lors de la quantification. Un ensemble de données représentatives est choisi pour couvrir la distribution des valeurs d'entrée que le modèle rencontrera lors de son utilisation en production.
Le processus d'extraction des données représentatives peut être décrit comme suit :
- Calcul des statistiques : Pour chaque couche du modèle, on calcule les valeurs min et max des données représentatives.
-
Détermination du scale : On peut déterminer le facteur d'échelle comme suit :
scale = (max_value - min_value) / (max_int_value - min_int_value) -
Calcul du zero_point : Le
zero_pointest calculé pour aligner la valeur 0 dans le domaine des entiers avec le domaine des valeurs flottantes :zero_point = round(-min_value / scale)
3. Comment fonctionne la quantification de la plage dynamique après l’entraˆınement dans TFLite ?¶
La quantification de la plage dynamique dans TensorFlow Lite (TFLite) consiste à convertir les poids et les activations du modèle en valeurs entières après l'entraînement tout en préservant la précision du modèle.
Ce processus peut être décomposé en plusieurs étapes :
- Calcul des statistiques : TFLite utilise les données représentatives pour calculer les valeurs min et max des poids et des activations.
-
Application des formules de quantification : La quantification est ensuite appliquée de la manière suivante pour les poids :
quantized_weight = round(weight / scale) + zero_point -
Stockage des paramètres : Les paramètres quantifiés et les valeurs
scaleetzero_pointsont stockés dans le modèle TFLite pour être utilisés lors de l'inférence. - Utilisation en production : Pendant l'inférence, TFLite utilise les paramètres quantifiés pour effectuer les calculs tout en minimisant la perte de précision par rapport au modèle original.