Dieser Artikel ist der vorherige Artikel "Die Geschichte, dass die Datensatzfunktion, die mit TensorFlow verwendet werden kann, stark war" "[[TF2.0-Anwendung] tf.data. Es handelt sich um eine weiter verbesserte Version der Datenerweiterung, die in "Datenerweiterung mit Datensatz schneller machen" (https://qiita.com/Suguru_Toyohara/items/49c2914b21615b554afa) ein wenig angesprochen wurde.
Bei Verwendung des Systems "tf.data.Dataset" zur Geschwindigkeitsverbesserung und des Systems "keras.preprocessing.image" ** Es ist gelungen, Code zu realisieren, der parallel verarbeitet werden kann. ** ** ** Ich werde den eigentlichen Mechanismus und den Hintergrund an dieser Stelle neben den Code setzen.
Ich werde den Code unten setzen
Lassen Sie uns zunächst die experimentelle Umgebung vorbereiten.
init
import tensorflow as tf
import tensorflow.keras as keras
import matplotlib.pyplot as plt
import sklearn
import numpy as np
from tqdm import tqdm
(tr_x,tr_y),(te_x,te_y)=keras.datasets.cifar10.load_data()
tr_x, te_x = tr_x/255.0, te_x/255.0
tr_y, te_y = tr_y.reshape(-1,1), te_y.reshape(-1,1)
model = keras.models.Sequential()
model.add(keras.layers.Convolution2D(32,3,padding="same",activation="relu",input_shape=(32,32,3)))
model.add(keras.layers.Convolution2D(32,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(32,3,padding="same",activation="relu"))
model.add(keras.layers.MaxPooling2D())
model.add(keras.layers.Convolution2D(128,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(128,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(128,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(128,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(128,3,padding="same",activation="relu"))
model.add(keras.layers.MaxPooling2D())
model.add(keras.layers.Convolution2D(256,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(256,3,padding="same",activation="relu"))
model.add(keras.layers.Convolution2D(256,3,padding="same",activation="relu"))
model.add(keras.layers.GlobalAveragePooling2D())
model.add(keras.layers.Dense(1000,activation="relu"))
model.add(keras.layers.Dense(128,activation="relu"))
model.add(keras.layers.Dense(10,activation="softmax"))
model.compile(loss="sparse_categorical_crossentropy",metrics=["accuracy"])
Lassen Sie uns zuerst keras.preprocessing.image.random_rotate
ausdrücken, damit dies mit .map
durchgeführt werden kann.
random_rotate
from tensorflow.keras.preprocessing.image import random_rotation
from joblib import Parallel, delayed
def r_rotate(imgs, degree):
pics=imgs.numpy()
degree = degree.numpy()
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)( [delayed(random_rotation)(pic, degree, 0, 1, 2) for pic in pics] )
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=random_rotation(pics, degree, 0, 1, 2)
return X
@tf.function
def random_rotate(imgs, label):
x = tf.py_function(r_rotate,[imgs,30],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Jetzt funktioniert es tatsächlich. Verschieben wir es und sehen uns die Daten an.
Daten anzeigen
labels = np.array([
'airplane',
'automobile',
'bird',
'cat',
'deer',
'dog',
'frog',
'horse',
'ship',
'truck'])
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128).map(random_rotate)
plt.figure(figsize=(10,10),facecolor="white")
for b_img,b_label in tr_ds:
for i, img,label in zip(range(25),b_img,b_label):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(img)
plt.xlabel(labels[label])
break
plt.show()
Lassen Sie uns überprüfen, wie schnell es tatsächlich sein wird. Zunächst war die Geschwindigkeit in "[TF2.0-Anwendung] tf.data.Dataset zur Beschleunigung der Datenerweiterung" wie folgt.
Ergebnis
Train on 50000 samples
50000/50000 [==============================] - 9s 175us/sample - loss: 2.3420 - accuracy: 0.1197
Train on 50000 samples
50000/50000 [==============================] - 7s 131us/sample - loss: 2.0576 - accuracy: 0.2349
Train on 50000 samples
50000/50000 [==============================] - 7s 132us/sample - loss: 1.7687 - accuracy: 0.3435
Train on 50000 samples
50000/50000 [==============================] - 7s 132us/sample - loss: 1.5947 - accuracy: 0.4103
Train on 50000 samples
50000/50000 [==============================] - 7s 132us/sample - loss: 1.4540 - accuracy: 0.4705
CPU times: user 1min 33s, sys: 8.03 s, total: 1min 41s
Wall time: 1min 14s
Als nächstes werde ich den Code und die Ergebnisse der vorherigen Implementierung veröffentlichen.
dataset
%%time
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000)
tr_ds = tr_ds.batch(tr_x.shape[0]).map(random_rotate).repeat(5)
tr_ds = tr_ds.prefetch(tf.data.experimental.AUTOTUNE)
for img,label in tr_ds:
model.fit(x=img,y=label,batch_size=128)
Ergebnis
Train on 50000 samples
50000/50000 [==============================] - 9s 176us/sample - loss: 1.3960 - accuracy: 0.5021
Train on 50000 samples
50000/50000 [==============================] - 9s 173us/sample - loss: 1.2899 - accuracy: 0.5430
Train on 50000 samples
50000/50000 [==============================] - 9s 175us/sample - loss: 1.2082 - accuracy: 0.5750
Train on 50000 samples
50000/50000 [==============================] - 9s 171us/sample - loss: 1.1050 - accuracy: 0.6133
Train on 50000 samples
50000/50000 [==============================] - 7s 132us/sample - loss: 1.0326 - accuracy: 0.6405
CPU times: user 52 s, sys: 15.4 s, total: 1min 7s
Wall time: 48.7 s
Ist es ein Gefühl, dass die Vorverarbeitungszuordnung auf der CPU funktioniert, während die GPU zu bis zu 90% läuft? Da es insgesamt 48,7 Sekunden sind, kann es um etwa 25 Sekunden verkürzt werden. Außerdem betrug die Zeit ohne Karte 35,1 Sekunden, sodass Sie sehen können, dass die Datenerweiterung relativ schnell durchgeführt werden kann. Und wenn Sie es auf die gleiche Weise tun, können Sie das gesamte System "keras.preprocessing.image" verwenden. ** ** **
show_data
def show_data(tf_dataset):
for b_img,b_label in tf_dataset:
for i, img,label in zip(range(25),b_img,b_label):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(img)
plt.xlabel(labels[label])
break
plt.show()
random_shift
Sie können bis zu welchem Prozentsatz der Verschiebung zufällig angeben.
random_shift
from tensorflow.keras.preprocessing.image import random_shift
from joblib import Parallel, delayed
def r_shift(imgs,wrg,hrg):
pics=imgs.numpy()
w = wrg.numpy()
h = wrg.numpy()
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)( [delayed(random_shift)(pic,w,h,0,1,2) for pic in pics] )
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=random_shift(pics, w,h, 0, 1, 2)
return X
@tf.function
def tf_random_shift(imgs, label):
x = tf.py_function(r_shift,[imgs,0.3,0.3],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Datenvisualisierung
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128).map(tf_random_shift)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
random_shear
Es kann verzerrt sein. (Ich kenne die Details nicht)
random_shear
from tensorflow.keras.preprocessing.image import random_shear
def r_shear(imgs,degree):
pics=imgs.numpy()
degree = degree.numpy()
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)( [delayed(random_shear)(pic,degree,0,1,2) for pic in pics] )
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=random_shear(pics,degree,0,1,2)
return X
@tf.function
def tf_random_shear(imgs, label):
x = tf.py_function(r_shear,[imgs,30],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Datenbestätigung
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128).map(tf_random_shear)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
random_zoom
Zoomt zufällig.
random_zoom
from tensorflow.keras.preprocessing.image import random_zoom
def r_zoom(imgs,range_w,range_h):
pics=imgs.numpy()
zoom_range = (range_w.numpy(),range_h.numpy())
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)( [delayed(random_zoom)(pic,zoom_range,0,1,2) for pic in pics] )
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=random_zoom(pics,zoom_range,0,1,2)
return X
@tf.function
def tf_random_zoom(imgs, label):
x = tf.py_function(r_zoom,[imgs,0.5,0.5],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Ausgabeergebnis
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128).map(tf_random_zoom)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
Es sieht aus wie die gleiche Größe ... Lassen Sie es uns verbessern.
enhanced
from tensorflow.keras.preprocessing.image import random_zoom
import random
def zoom_range_gen(random_state):
while True:
x=random.uniform(random_state[0],random_state[1])
yield (x,x)
def r_zoom(imgs):
pics=imgs.numpy()
random_state = [0.5,1.5]
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)( [delayed(random_zoom)(pic,(x,y),0,1,2) for pic,(x,y) in zip(pics,zoom_range_gen(random_state))])
X=np.asarray(X)
elif tf.rank(imgs)==3:
zoom_range=next(zoom_range_gen)
X=random_zoom(pics,zoom_range,0,1,2)
return X
@tf.function
def tf_random_zoom_enhanced(imgs, label):
x = tf.py_function(r_zoom,[imgs],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Lassen Sie uns die Daten überprüfen
Bestätigung der Daten
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128).map(tf_random_zoom_enhanced)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
Es fühlt sich gut an! !!
Implementieren Sie als Nächstes die Erweiterung in diesem Blog "Zusammenfassung der Datenerweiterung von Bildern in NumPy". Die Augmentation in Keras basiert auf Numpy, sodass Sie jetzt die Numpy-basierte Augmentation implementieren können.
Ich werde das Bild von Neko aus dem Blog "Zusammenfassung der Datenerweiterung von Bildern in NumPy" zitieren. Ich werde auch den Inhalt dieser Implementierung zitieren. Ich werde auch die Quelle in den Code schreiben.
random-flip
Lassen Sie uns eine zufällige Umkehrung von links nach rechts implementieren. Dies wurde bereits im TF-System implementiert, daher werden wir es verwenden.
random-flip
@tf.function
def flip_left_right(image,label):
return tf.image.random_flip_left_right(image),label
@tf.function
def flip_up_down(image,label):
return tf.image.random_flip_up_down(image),label
Bestätigung der Daten
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128)
tr_ds = tr_ds.map(flip_left_right).map(flip_up_down)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
random-clip
Hier verwenden wir Scale Augmentation in Blog.
Für die Implementierung habe ich auf den [Blog] verwiesen (https://www.kumilog.net/entry/numpy-data-augmentation).
random-clip
from PIL import Image
def random_crop(pic, crop_size=(28, 28)):
try:
h, w, c = pic.shape
except ValueError:
raise ValueError("4Ds image can't decode")
#Bestimmen Sie den oberen linken Punkt des Bildes im angegebenen Abschnitt
top = np.random.randint(0, h - crop_size[0])
left = np.random.randint(0, w - crop_size[1])
#Bestimmen Sie den unteren rechten Punkt entsprechend der Größe
bottom = top + crop_size[0]
right = left + crop_size[1]
#Schneiden Sie nur den Schnittpunkt des oberen linken Punkts und des unteren rechten Punkts aus
pic = pic[top:bottom, left:right, :]
return pic
def scale_augmentation(pic, scale_range=(38, 80), crop_size=32):
scale_size = np.random.randint(*scale_range)
Ppic = Image.fromarray(pic)
Ppic = Ppic.resize((scale_size,scale_size),resample=1)
pic = np.asarray(Ppic)
return random_crop(pic, (crop_size, crop_size))
def r_crop(imgs):
pics=imgs.numpy()
pics=np.asarray(pics * 255.0,dtype=np.uint8)
random_state = (38,60)
crop_size=32
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)([delayed(scale_augmentation)(pic,random_state,crop_size) for pic in pics ])
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=scale_augmentation(pics,random_state,crop_size)
X=X/255.0
return X
@tf.function
def tf_random_crop(imgs, label):
x = tf.py_function(r_crop,[imgs],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Datenbestätigung
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128)
tr_ds = tr_ds.map(tf_random_crop)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
random-erasing
Implementieren Sie dies. Für die Implementierung habe ich auf [Blog] verwiesen (https://www.kumilog.net/entry/numpy-data-augmentation).
random_erasing
def random_erasing(pic, p=0.5, s=(0.02, 0.4), r=(0.3, 3)):
#Ob maskiert oder nicht
if np.random.rand() > p:
return pic
#Bestimmen Sie zufällig den zu maskierenden Pixelwert
mask_value = np.random.random()
try:
h, w, c = pic.shape
except ValueError:
raise ValueError("4Ds image can't decode")
#Maskengröße s des Originalbildes(0.02~0.4)Entscheide dich zufällig aus dem doppelten Bereich
mask_area = np.random.randint(h * w * s[0], h * w * s[1])
#Seitenverhältnis der Maske r(0.3~3)Zufällig aus dem Bereich von entschieden
mask_aspect_ratio = np.random.rand() * r[1] + r[0]
#Bestimmen Sie die Höhe und Breite der Maske anhand der Größe und des Seitenverhältnisses der Maske
#Berechnete Höhe und Breite(Entweder)Kann größer als das Originalbild sein, korrigieren Sie es also
mask_height = int(np.sqrt(mask_area / mask_aspect_ratio))
if mask_height > h - 1:
mask_height = h - 1
mask_width = int(mask_aspect_ratio * mask_height)
if mask_width > w - 1:
mask_width = w - 1
top = np.random.randint(0, h - mask_height)
left = np.random.randint(0, w - mask_width)
bottom = top + mask_height
right = left + mask_width
pic[top:bottom, left:right, :].fill(mask_value)
return pic
def r_erase(imgs):
pics=imgs.numpy()
if tf.rank(imgs)==4:
X=Parallel(n_jobs=-1)([delayed(random_erasing)(pic) for pic in pics ])
X=np.asarray(X)
elif tf.rank(imgs)==3:
X=random_erasing(pics)
return X
@tf.function
def tf_random_erase(imgs, label):
x = tf.py_function(r_erase,[imgs],[tf.float32])
X = x[0]
X.set_shape(imgs.shape)
return X, label
Bestätigung der Daten
tr_ds = tf.data.Dataset.from_tensor_slices((tr_x,tr_y)).shuffle(40000).batch(128)
tr_ds = tr_ds.map(tf_random_erase)
plt.figure(figsize=(10,10),facecolor="white")
show_data(tr_ds)
Mit CIFAR10 bin ich ein wenig überwältigt und es gibt einige Dinge, die ich nicht verstehe ...
Hier sind einige Dinge zu beachten, wenn Sie Code schreiben. Es ist eine grundlegende Sache, also bin ich sicher, dass einige von Ihnen denken, dass es etwas ist. Überraschenderweise gab es nur Fallstricke, deshalb werde ich sie hier aufschreiben.
tf.data.Dataset.map
Hier gibt es einige Fallstricke, aber das Verhalten während des Mappings ist vom Typ "Tensor".
... was ich sagen möchte ist, dass ** Eager Execution auf Tensor, der von .map
verarbeitet wird, nicht funktioniert. ** ** **
Mit anderen Worten, normale Multiplikation usw. kann mit @ tf.function
sauber in eine TF-Operation umgewandelt werden.
Andernfalls können Operationen, die ohne reelle Zahlen nicht ausgeführt werden können, wie z. B. ".numpy ()", nicht verwendet werden **. ** ** **
Ich denke, es ist leicht zu verstehen, wenn Sie denken, dass es nur als Ausdruck wie x + y = z beschrieben wird.
Dort können Sie den Eager-Modus aktivieren.
Was zu tun ist, ist ** tf.py_function
zu verwenden. ** ** **
Der Grafikmodus ist wie eine Formel. Das habe ich mit Sess.run in der TF1.x-Serie gemacht. Indem Sie so etwas wie die Formel x + y = z entwerfen und dann Variablen Werte zuweisen (dh Sitzung ausführen) 2 + 3 = 5 Z Tensor hat zum ersten Mal einen Wert von 5. Hier war das TF1.x-System schwer zu verstehen.
Der Eager-Modus ist wie die Eingabe eines Ausdrucks und die Ausgabe des sofort ausgeführten Werts. Sess.run wird automatisch ausgeführt und Graph wird beibehalten, sodass es leicht zu verstehen scheint. (Ich bin mit diesem Bereich überhaupt nicht vertraut, daher hoffe ich, dass Sie sich auf den offiziellen Leitfaden beziehen können.) (Bitte sagen Sie mir, wenn Sie einen Fehler machen)
tf.py_function
tf.py_function
ist eine Funktion, die teilweise im Eager-Modus ausgeführt werden kann, wie in Guide beschrieben.
Mit anderen Worten, stellen Sie hier einfach die Black-Box-Funktion f (x) ein und geben Sie nur an, was herauskommt. Sie wird dann im Grafikmodus ausgeführt.
Es wird so sein.
Als Ausdruck möchte die TF-Seite einen Ausdruck wie x + f (a, b) = y, und hier werden die Eingabe- und Ausgabedatentypen benötigt.
py_Pseudocode für die Funktion
def function(Eingabe 1,Eingabe 2):
#Hier läuft es im Eager-Modus
#Etwas verarbeiten
Rückgabe 1,Ausgabe 2
[Ausgabe 1,Ausgabe 2] = tf.py_function(function,[Eingabe 1,Eingabe 2],[Ausgabe 1の型,Ausgabe 2の型])
Insbesondere wird es so sein.
py_function
def function(data1,data2):
return data1+data2,data1*data2
@tf.function
def process(tensor1,tensor2):
[data1,data2]=tf.py_function(function,[tensor1,tensor2],[tf.float32,tf.float32])
return data1, data2
Mit anderen Worten, die Funktionsfunktion wird hier zur Laufzeit im Eager-Modus ausgeführt, sodass sie zu "tf.Tensor" mit einem Wert in "Tensor" wird.
tf.Tensor
und Tensor
unterscheiden sich im Eager-Modus und im Graph-Modus. Seien Sie also vorsichtig **
Dies geschieht im Eager-Modus und "tf.Tensor" wird eingeblendet. Es ist also in Ordnung, das erste ".numpy ()" auszuführen und das Ergebnis als numpy zurückzugeben.
Hier entstehen viele Missverständnisse.
tf.data.Dataset.map
funktioniert zunächst nur im Grafikmodus. Darüber hinaus müssen einige im Eager-Modus ausgeführt werden.
Dies scheint das Verhalten von "tf.data.Dataset.from_tensor_slices" zu sein. (Es tut mir leid, weil es keine genauen Informationen sind) Und wenn Daten entladen werden, ist dies wie folgt.
Wenn Sie in diesem Sinne codieren, können Sie reibungslos codieren, ohne durch mysteriöse Fehler verwirrt zu werden.
Ich glaube, ich konnte Ihnen damit sagen, wie Sie eine universelle Datenerweiterung entwickeln können. Ich möchte so etwas noch machen! Ich hoffe, dass diejenigen, die das sagen, es auf die gleiche Weise schaffen. Ich bin wirklich erleichtert, das Rätsel der "py_function" zu lösen. Bitte verwenden Sie alle Mittel.
Dieser Blog "Zusammenfassung der Datenerweiterung von Bildern in NumPy" war bei der Implementierung sehr hilfreich. Ich möchte diese Gelegenheit nutzen, um Ihnen zu danken.
Recommended Posts