[PYTHON] Modèle de prédiction de température fonctionnant sur edgetpu (corail)

introduction

J'ai créé un modèle de prédiction de température de tensorflow lite qui fonctionne sur edgetpu (coral) connecté à Raspberry pi4. La version Tensorflow est 2.3.1, la version du compilateur edgetpu est 15.0.340273435 et la version d'exécution edgetpu est 2.14.1.

Flux principal

  1. Créez et entraînez un modèle unidimensionnel basé sur CNN à l'aide de Keras de Tensorflow sur Google Colab

  2. Après l'entraînement, quantifiez le modèle et convertissez-le en modèle tensorflowlite

  3. Compilez avec le compilateur edgetpu pour travailler avec edgetpu

  4. Prédire en utilisant les données de test sur le Raspberry pi4 et prédire la température du processeur du Raspberry pi4

1. Création / apprentissage de modèles

Préparation du jeu de données

En utilisant le site de l'Agence météorologique où vous pouvez rechercher des données météorologiques passées, un endroit pour une journée Nous collectons des données sur la température moyenne depuis environ 20 ans.

Créer un modèle

Un modèle unidimensionnel basé sur CNN a été créé à l'aide de l'API fonctionnelle de Keras, qui prend la température moyenne de 30 jours comme entrée et prédit la température moyenne du jour suivant. ..

inputs = tf.keras.Input(shape=(30,1))
cnn1 = tf.keras.layers.Conv1D(filters=1,kernel_size=10,strides=1,activation='relu',input_shape=(30,1))
cnn2 = tf.keras.layers.Conv1D(filters=1,kernel_size=5,strides=1,activation='relu')
cnn3 = tf.keras.layers.Conv1D(filters=1,kernel_size=3,strides=1,activation='relu')
dense1 = tf.keras.layers.Dense(units=8,activation='relu')
dense2 = tf.keras.layers.Dense(units=1)
x = cnn1(inputs)
x = cnn2(x)
x = cnn3(x)
x = tf.keras.layers.Flatten()(x)
x = dense1(x)
outputs = dense2(x)
model = tf.keras.Model(inputs=inputs,outputs=outputs)
model.compile(optimizer="Adam",loss="mean_squared_error",
                               metrics="binary_accuracy")
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_14 (InputLayer)        [(None, 30, 1)]           0         
_________________________________________________________________
conv1d_31 (Conv1D)           (None, 21, 1)             11        
_________________________________________________________________
conv1d_32 (Conv1D)           (None, 17, 1)             6         
_________________________________________________________________
conv1d_33 (Conv1D)           (None, 15, 1)             4         
_________________________________________________________________
flatten_5 (Flatten)          (None, 15)                0         
_________________________________________________________________
dense_24 (Dense)             (None, 8)                 128       
_________________________________________________________________
dense_25 (Dense)             (None, 1)                 9         
=================================================================
Total params: 158
Trainable params: 158
Non-trainable params: 0
_________________________________________________________________
"""

Apprentissage de modèle

Je me suis entraîné avec une taille de lot de 50 et un numéro d'époque de 30.

model.fit(x=in_temp,y=out_temp,batch_size=50,epochs=30)

2. Quantification du modèle

Il doit être quantifié en un entier 8 bits pour s'exécuter sur edgetpu. Puisqu'il est nécessaire de fixer la taille d'entrée pour la quantification, spécifiez `` sigantures '' et enregistrez le modèle une fois. Ici, la taille d'entrée est définie sur 1x30x1.

opt = tf.function(lambda x:model(x))
BACTH_SIZE = 1
STEPS = 30
INPUT_SIZE = 1
concrete_func = opt.get_concrete_function(tf.TensorSpec([BACTH_SIZE,STEPS,INPUT_SIZE],
                                                        model.inputs[0].dtype,name="inputs")
)
model.save('/content/weather',save_format="tf",signatures=concrete_func)

Puis quantifiez le modèle. Consultez la documentation de Tensorflow (https://www.tensorflow.org/lite/performance/post_training_integer_quant) pour plus d'informations. in_tempLe tableau numpy nd est-il entré lors de l'entraînement du modèle.

conv_data = in_temp[0]
conv_data = conv_data.reshape(1,30,1)

def representative_dataset_gen():
  for i in range(len(conv_data)):
    yield [conv_data[i]]

converter_edgetpu = tf.lite.TFLiteConverter.from_saved_model("/content/weather")
converter_edgetpu.optimizations = [tf.lite.Optimize.DEFAULT]
converter_edgetpu.representative_dataset = representative_dataset_gen
converter_edgetpu.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter_edgetpu.inference_input_type = tf.uint8
converter_edgetpu.inference_output_type = tf.uint8
converter_edgetpu.experimental_new_converter = True
tflite = converter_edgetpu.convert()

Enfin, enregistrez le modèle.

open("cnn_weather_lite_quantized.tflite","wb").write(tflite)

Compiler avec le compilateur edgetpu

Installer le compilateur edgetpu

Installez le compilateur edgetpu sur Google Colab. Voir Documentation pour plus de détails sur l'installation.

Directement parce que l'architecture CPU nécessite x86-64 comme indiqué dans la Documentation et que l'architecture CPU de Raspberry pi4B est ARMv8. Je ne pense pas qu'il puisse être installé sur Raspberry pi 4. (Architecture CPU de Raspberry pi: https://nw-electric.way-nifty.com/blog/2020/02/post-6c09ad.html)

!curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
!echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list
!sudo apt -y update
!sudo apt-get install edgetpu-compiler

Compiler avec le compilateur edgetpu

Référence: https://coral.ai/docs/edgetpu/compiler/#usage

!edgetpu_compiler /content/cnn_weather_lite_quantized.tflite

Prévoir

Prédite par les données de test

Depuis le site de l'Agence météorologique, nous avons à nouveau préparé les données de la température quotidienne moyenne pendant 30 jours. Ensuite, j'ai exécuté le code suivant (lors de l'utilisation d'edgetpu) sur le Raspberry pi pour prédire la température du jour suivant. Nous avons également mesuré le temps d'exécution et comparé le temps à l'utilisation du processeur. Le code d'inférence était basé sur la section «Charger et exécuter le modèle en Python» du site Tensorflow. Il sera automatiquement traduit en japonais, donc si la traduction est incorrecte, nous vous recommandons de la lire en anglais.

import numpy as np
import pandas as pd
import tflite_runtime.interpreter as tflite
import time

def main(args):
    interpreter = tflite.Interpreter('/home/pi/cnn_weather/cnn_weather_lite_quantized_edgetpu.tflite',
    experimental_delegates=[tflite.load_delegate('libedgetpu.so.1')])
    
    data = pd.read_csv('/home/pi/cnn_weather/test.csv')
    test_data = np.asarray(data.loc[:len(data),"Température moyenne"],dtype=np.uint8)
    test_data = test_data.reshape(1,30,1)
    
    start = time.perf_counter()
    
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    input_shape = input_details[0]['shape']
    interpreter.set_tensor(input_details[0]['index'],test_data)
    
    interpreter.invoke()
    
    output_data = interpreter.get_tensor(output_details[0]['index'])
    
    end = time.perf_counter()
    
    print("The next day's temperature is " + str(output_data[0,0]) + " degrees Celsius.")
    print("It took " + str((end-start)*1000) + " ms.")
    
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Le résultat est affiché. Le haut est le résultat de l'exécution avec edgetpu, le milieu est le résultat de l'exécution du modèle non quantifié sur le CPU, et le bas est le résultat de l'exécution du modèle quantifié sur le CPU. La quantification le rend plus rapide, mais l'utilisation d'edgetpu ralentit ... Le temps d'exécution étant de 2 ms, l'appel d'edgetpu, etc., peut prendre plus de temps en utilisant edgetpu. En passant, vous pouvez voir que la précision diminue considérablement lorsqu'elle est quantifiée. (Les données du test vont de la fin septembre à la fin octobre, et comme il commence à environ 22 ° C et se termine à environ 18 ° C, je pense que 24 ° C et 26 ° C sont tout à fait hors de propos.)

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/edgetpu_time.py
The next day's temperature is 24 degrees Celsius.
It took 2.218683000137389 ms.

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/cpu_time.py
The next day's temperature is 17.671713 degrees Celsius.
It took 3.6856149999948684 ms.

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/cpu_quantized_time.py
The next day's temperature is 26 degrees Celsius.
It took 1.4244879994294024 ms.

Prédiction de la température du processeur

Je l'exécute sur un petit appareil appelé Raspberry pi, donc je voulais essayer quelque chose comme la prédiction en temps réel. Je voulais le prédire en fonction de la température extérieure, mais il semble difficile de le faire moi-même car il n'y a pas de capteur, j'ai donc essayé de le prédire en fonction de la température du processeur. J'ai pris la température du processeur avec $ cat / sys / class / thermal / thermal_zone0 / temp '' toutes les secondes, et j'ai prédit la température après 1 seconde lorsque 30 secondes ont été recueillies. De plus, $ cat / sys / class / thermal / thermal_zone0 / temp '' renvoie la valeur de la température du processeur multipliée par 1000, j'ai donc utilisé le résultat de sortie divisé par 1000.

Voici le code que j'ai exécuté sur le Raspberry pi. (Seul le code lors de l'utilisation d'edgetpu est affiché)

import numpy as np
import tflite_runtime.interpreter as tflite
import time
import subprocess

def main(args):
    start = time.perf_counter()
    interpreter = tflite.Interpreter('/home/pi/cnn_weather/cnn_weather_lite_quantized_edgetpu.tflite',
    experimental_delegates=[tflite.load_delegate('libedgetpu.so.1')])
    
    data = list()
    for i in range(30):
        res = subprocess.run(['cat', '/sys/class/thermal/thermal_zone0/temp'],
        stdout=subprocess.PIPE)
        get_start = time.perf_counter()
        result = res.stdout.decode('utf-8')
        result = int(result)/1000
        data.append(result)
        print(result,end='℃ ')
        if (i+1)%10 == 0:
            print()
        get_end = time.perf_counter()
        get_time = get_end-get_start
        
        if get_time < 1:
            time.sleep(1-get_time)
        else:
            print("Took " + str(get_time) + " s to get " +  str(i) + "'s temp.")
    
    pre_start = time.perf_counter()
    np_data = np.asarray(data,dtype=np.uint8).reshape(1,30,1)
    
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    input_shape = input_details[0]['shape']
    interpreter.set_tensor(input_details[0]['index'],np_data)
    interpreter.invoke()
    
    pred = interpreter.get_tensor(output_details[0]['index'])
    
    pre_end = time.perf_counter()
    pre_time = pre_end - pre_start
    if pre_time < 1:
        print("The cpu's temp will be " + str(pred[0,0]) + "℃ in " + 
        str(1-pre_time) + " s.")
        
        time.sleep(1-pre_time)
        res = subprocess.run(['cat', '/sys/class/thermal/thermal_zone0/temp'],
        stdout=subprocess.PIPE)
        result = res.stdout.decode('utf-8')
        result = int(result)/1000
        print("The cpu's temp is " + str(result) + "℃.")
    else:
        print("The cpu's temp must have been " + str(pred[0,0]) + "℃ " + 
        str(1-pre_time) + " s ago.")
    
    end = time.perf_counter()
    print("Took " + str(end-start) + " s to run this code.")
    
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Le résultat est affiché. Le haut correspond à l'utilisation d'edgetpu, le milieu correspond à l'utilisation d'un modèle non quantifié et le bas correspond à l'utilisation d'un modèle quantifié. Les températures répertoriées sont les données de température du processeur utilisées pour la prédiction. Après tout, le modèle quantifié a une sortie non pertinente supérieure à 100 ° C. De plus, comme avant, il faut du temps pour utiliser edgetpu. Cette fois, je mesurais le temps non seulement pour l'inférence, mais aussi pour appeler `` tf.lite.Interpreter '', de sorte que cette partie peut également prendre du temps en utilisant edgetpu.

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/predict_edgetpu.py
63.783℃ 64.757℃ 63.783℃ 63.783℃ 63.296℃ 62.809℃ 63.296℃ 63.296℃ 62.809℃ 62.809℃ 
62.809℃ 63.296℃ 62.322℃ 62.809℃ 63.783℃ 62.809℃ 63.783℃ 63.783℃ 62.322℃ 62.809℃ 
62.322℃ 63.783℃ 62.809℃ 62.322℃ 62.322℃ 62.322℃ 62.322℃ 62.322℃ 62.322℃ 63.296℃ 
The cpu's temp will be 105℃ in 0.9969898569997895 s.
The cpu's temp is 61.835℃.
Took 34.21252226499928 s to run this code.

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/predict_cpu.py
63.783℃ 63.783℃ 63.296℃ 62.809℃ 63.783℃ 63.296℃ 62.809℃ 63.296℃ 62.809℃ 62.322℃ 
62.322℃ 62.322℃ 62.809℃ 62.322℃ 61.835℃ 62.322℃ 62.322℃ 61.348℃ 62.322℃ 62.322℃ 
63.296℃ 61.835℃ 62.322℃ 61.835℃ 61.348℃ 61.348℃ 61.835℃ 62.322℃ 62.809℃ 62.322℃ 
The cpu's temp will be 62.17556℃ in 0.9969654129999981 s.
The cpu's temp is 62.322℃.
Took 31.404364756001087 s to run this code.

pi@raspberrypi:~$ python3 /home/pi/cnn_weather/predict_cpu_quantized.py
63.296℃ 63.296℃ 62.809℃ 62.322℃ 62.322℃ 61.835℃ 61.835℃ 62.322℃ 61.835℃ 62.322℃ 
62.809℃ 62.322℃ 62.809℃ 62.322℃ 60.861℃ 62.322℃ 61.835℃ 61.835℃ 62.322℃ 61.835℃ 
61.835℃ 61.835℃ 61.348℃ 62.322℃ 60.861℃ 61.348℃ 62.322℃ 61.348℃ 61.835℃ 61.348℃ 
The cpu's temp will be 101℃ in 0.9984136980001495 s.
The cpu's temp is 61.835℃.
Took 31.43542323499969 s to run this code.

finalement

J'ai créé et exécuté un modèle de prédiction de température pour tensorflowlite qui fonctionne sur edgetpu (coral) connecté à Raspberry pi4. La quantification a considérablement réduit la précision (au contraire, elle est devenue un modèle presque dénué de sens), et le résultat était que le temps d'exécution était plus long lors de l'utilisation d'edgetpu que lors de l'utilisation du processeur. Cette fois, plutôt que de créer un modèle avec une bonne précision, créer un modèle qui déduit à l'aide d'edgetpu était l'objectif pour le moment, je vais donc terminer ici pour le moment. Tous les modèles de données, de code et de tensorflowlite utilisés cette fois-ci se trouvent sur github.

Merci d'avoir regardé jusqu'à présent. Ceci est mon premier article, alors n'hésitez pas à commenter si vous avez des préoccupations ou des suggestions.

De côté

J'essayais de faire la même chose avec LSTM avant d'utiliser 1D CNN, mais j'ai eu une erreur comme celle de ici Je suis resté coincé, alors j'ai décidé d'utiliser un CNN unidimensionnel. En regardant le problème lié à, il semble qu'il est actuellement impossible de quantifier les modèles basés sur RNN tels que le LSTM. (La version Tensorflow liée est 2.2.0, cette fois j'ai utilisé 2.3.1)

Bien qu'il ne s'agisse pas de la même déclaration d'erreur, il semble que les systèmes RNN tels que LSTM ne prennent pas en charge la quantification même dans Erreurs qui semblent être liées. On m'a demandé s'il y en avait un. De plus, j'ai pu le convertir en modèle tensorflow lite et l'exécuter avec Raspberry pi à l'état non quantifié.

Recommended Posts

Modèle de prédiction de température fonctionnant sur edgetpu (corail)
Construction du modèle de prédiction ①