Better performance with the tf.data API J'ai conçu le chargeur de données pour CNN en me référant à la page ci-dessus et j'ai réglé la vitesse du chargeur de données dans Tensorflow. En conclusion, j'ai essayé quelques techniques d'accélération, mais malheureusement je n'ai pas pu aller plus vite que l'implémentation de base.
tf.data Tensorflow fournit une API pour le pipeline d'entrée appelée tf.data. Lors du chargement de données qui ne rentrent pas dans la RAM, comme un fichier image, dans le modèle, tf.data peut être utilisé pour obtenir un traitement à grande vitesse car le prétraitement des données et l'apprentissage NN sont effectués en parallèle en interne. Le mécanisme approximatif est le suivant.
Si vous l'implémentez avec le générateur python, etc., il sera inefficace car l'autre sera inactif pendant que le processeur ou le GPU est en cours d'exécution, mais si vous l'implémentez avec tf.data, vous pouvez raccourcir le temps d'inactivité. Sera.
La mise en œuvre est expliquée à ici et peut être mise en œuvre avec relativement peu d'effort.
L'image d'ImageNet est enregistrée au format jpeg et chargée dans mobilenet. L'environnement expérimental est Google Colaboratory.
Introduction Utilisation basique de tf.data. Lisez les chemins des images enregistrées un par un et recadrez-les au hasard en une image 244x244.
train_img_paths = glob.glob(os.path.join(IMAGE_DIR, '*.jpg'))
train_img_paths.sort()
num_train_imgs = len(train_img_paths)
train_label = [1 for path in train_img_paths]
m = tf.keras.Sequential([
hub.KerasLayer("https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4", output_shape=[1], trainable=True)
])
m.build([None, IMAGE_SIZE[0], IMAGE_SIZE[1], IMAGE_SIZE[2]])
m.compile(loss=tf.keras.losses.BinaryCrossentropy(), optimizer='Adam')
def preprocessing(img_path, label):
img = tf.image.decode_image(tf.io.read_file(img_path))
img = tf.image.random_crop(img, size=IMAGE_SIZE)
img = tf.cast(img, tf.float32)
img = img / 255.0
label = tf.cast(label, tf.float32)
img.set_shape(IMAGE_SIZE)
return img, label
train_data = tf.data.Dataset.from_tensor_slices((train_img_paths, train_label))
train_data = train_data.shuffle(num_train_imgs).map(preprocessing).repeat().batch(batch_size).prefetch(buffer_size=AUTOTUNE)
time_start = time.time()
m.fit(train_data, epochs=epochs, steps_per_epoch=steps_per_epoch)
time_end = time.time()
print(f'Total time:{(time_end-time_start)/60.0:.3f}[min]')
print(f'Time per step:{(time_end-time_start)/steps_per_epoch*epochs:.3f} [sec]')
Total time:0.446[min]
Time per step:0.803 [sec]
Cela a pris environ 0,8 seconde par étape. À partir de là, je vais concevoir des moyens d'accélérer l'apprentissage.
Exécutez la fonction de mappage de l'objet Dataset en parallèle. Il doit être rapide car la partie extraction de données est traitée dans plusieurs processus.
Dans la section précédente
train_data = tf.data.Dataset.from_tensor_slices((train_img_paths, train_label))
train_data = train_data.shuffle(num_train_imgs).map(preprocessing).repeat().batch(batch_size).prefetch(buffer_size=AUTOTUNE)
Réécrivez la partie de comme suit.
train_data = tf.data.Dataset.from_tensor_slices((train_img_paths, train_label))
train_data = train_data.shuffle(num_train_imgs).repeat().map(preprocessing, num_parallel_calls=AUTOTUNE).batch(batch_size).prefetch(buffer_size=AUTOTUNE)
Total time:3.726[min]
Time per step:6.707 [sec]
Il est tard pour une raison quelconque. S'agit-il d'une spécification de Google Colaboratory? (Enquête requise)
La mise en cache est une fonction qui conserve temporairement les données lues dans la RAM ou le stockage.
train_data = tf.data.Dataset.from_tensor_slices((train_img_paths, train_label))
train_data = train_data.shuffle(num_train_imgs).repeat().map(preprocessing, num_parallel_calls=AUTOTUNE).batch(batch_size).cache()
Total time:7.014[min]
Time per step:12.625 [sec]
Encore une fois, nous n'avons pas pu l'accélérer. Je pense que la cause est que la fonction de carte est conçue pour lire l'image et convertir les données d'image en même temps. Vous avez besoin d'une structure qui sépare la lecture d'image et la conversion de données d'image. (Tâches futures)
La fonction de carte définie par l'utilisateur semble entraîner une surcharge pour des raisons de traitement. Par conséquent, il semble que ce sera plus rapide si la fonction de carte définie par l'utilisateur est vectorisée, c'est-à-dire que l'entrée est traitée en même temps. Plus précisément, il est recommandé de mettre en œuvre par traitement par lots → conversion de données au lieu de conversion de données → traitement par lots.
Je n'ai pas encore pu expérimenter en raison de contraintes de temps, mais dans l'expérience avec l'URL affichée au début de l'article, c'est jusqu'à 30 fois plus rapide.
J'ai essayé de paralléliser la fonction de carte et la mise en cache, mais aucun d'entre eux n'a conduit à une accélération.
Je pense qu'il y a plusieurs causes, il est donc nécessaire d'enquêter à l'avenir. Si vous avez des conseils, je vous serais reconnaissant de bien vouloir me le faire savoir.
Recommended Posts