Derzeit bin ich eine M2-Person mit Schwerpunkt CS. Normalerweise schreibe ich hauptsächlich Code für maschinelles Lernen in PyTorch. Es ist vorerst einfach zu schreiben. PyTorch heißt ** "Define by Run" **, und was gut ist, ist, dass Sie die Berechnungsergebnisse in der Mitte gleichzeitig mit dem Berechnungsdiagramm und dem Zeitpunkt des Sendens der Daten überprüfen können und das Debuggen einfach ist. Ich bin so ein PyTorch-Anhänger, aber dieses Mal musste ich Code in TensorFlow schreiben, also lasse ich ihn als Memo, damit ich das damalige Know-how nicht vergesse.
Bevor ich PyTorch berührte, konnte ich es verstehen, weil ich TensorFlow und Keras berührte, aber ich konnte den Inhalt nicht verstehen, nachdem ich TensorFlow2 geworden war, also war es diesmal eine gute Studie. Übrigens hat TensorFlow1 (TF1) die Methode des Datenflusses an die Stelle übernommen, an der der statische Graph mit der Methode ** "Definieren und Ausführen" ** erstellt wurde, jedoch in TensorFlow2 (TF2) ** ". Es verwendet dieselbe Methode wie Define by Run "** und PyTorch.
Dieser Artikel richtet sich an Personen, die mit TensorFlow2 maschinelles Lernen beginnen möchten. Wenn ich mir die Artikel anderer Leute ansehe, gibt es viele Artikel über TensorFlow1, und ich konnte nicht viele Artikel über TensorFlow2 (TF2) finden. Ich hoffe, dass dies für diejenigen hilfreich ist, die von nun an daran denken, TF2 zu berühren. Außerdem habe ich anstelle der sklearn-ähnlichen Lernmethode mit model.fit
usw. hauptsächlich die Expertenmethode im TensorFlow-Tutorial geschrieben, sodass ich hoffe, dass diejenigen, die interessiert sind, sie lesen können.
** 1. TensorFlow-Grundlagen ** ** 2. Einfaches Modellieren und Lernen mit Keras (Anfängerversion) ** ** 3. Transferlernen (+ Feinabstimmung) ** ** 4. Bauen Sie Ihr eigenes Modell ** ** 5. Modellbildung und Lernen mit TensorFLow2 (Expertenversion) **
** [1]. Bei Verwendung Ihres eigenen Datensatzes ** ** [2] Über Augmentaion ** [3]. TensorBoard [4]. TFRecord
Zunächst zu den Grundlagen.
Sie können eine Konstante mit "tf.constant (Wert, dtype = Keine, Form = Keine, Name =" Konstante ", verify_shape = False)" definieren.
>>> import tensorflow as tf
>>>
>>> tf.constant([1, 2, 3])
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 2, 3], dtype=int32)>
>>>
>>> b = tf.constant('Hello') #String ok
<tf.Tensor: shape=(), dtype=string, numpy=b'Hello'>
>>>
Wenn Sie "Form" angeben, haben alle Elemente den gleichen Wert.
>>> tf.constant(3, shape=[1, 3])
<tf.Tensor: shape=(1, 3), dtype=int32, numpy=array([[3, 3, 3]], dtype=int32)>
>>>
>>>
>>> tf.add(2,3)
<tf.Tensor: shape=(), dtype=int32, numpy=5>
>>>
>>> tf.subtract(5,3)
<tf.Tensor: shape=(), dtype=int32, numpy=2>
>>>
>>> tf.multiply(3,4)
<tf.Tensor: shape=(), dtype=int32, numpy=12>
>>>
>>> tf.divide(2,3)
0.6666666666666666
Verwenden Sie tf.convert_to_tensor
.
Verwenden Sie .numpy ()
für ein Numpy-Array.
>>> a = np.asarray([1,2,3])
>>> a
array([1, 2, 3])
>>> a.shape
(3,)
>>> tf.convert_to_tensor(a)
<tf.Tensor: shape=(3,), dtype=int64, numpy=array([1, 2, 3])>
>>> a
array([1, 2, 3])
>>> c = tf.convert_to_tensor(a)
>>> c
<tf.Tensor: shape=(3,), dtype=int64, numpy=array([1, 2, 3])>
>>> c.numpy()
array([1, 2, 3])
Fügen Sie die Dimensionsnummer "tf.expand_dims (Eingabe, Achse, Name = Keine)" hinzu Wird verwendet, wenn der Bildgröße eine Stapelgröße hinzugefügt wird
>>> a = tf.constant([2,3])
>>> a.shape
TensorShape([2])
>>> b = tf.expand_dims(a,0)
>>> b.shape
TensorShape([1, 2])
>>>
tf.stack(values, axis=0, name='stack')
>>> x = tf.constant([1, 4])
>>> y = tf.constant([2, 5])
>>> z = tf.constant([3, 6])
>>> tf.stack([x, y, z], axis=0)
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[1, 4],
[2, 5],
[3, 6]], dtype=int32)>
>>> tf.stack([x, y, z], axis=1)
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)>
>>>
tf.concat(values, axis, name='concat')
>>> t1 = [[1, 2, 3], [4, 5, 6]]
>>> t2 = [[7, 8, 9], [10, 11, 12]]
>>> tf.concat([t1,t2],0)
<tf.Tensor: shape=(4, 3), dtype=int32, numpy=
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]], dtype=int32)>
>>> tf.concat([t1,t2],1)
<tf.Tensor: shape=(2, 6), dtype=int32, numpy=
array([[ 1, 2, 3, 7, 8, 9],
[ 4, 5, 6, 10, 11, 12]], dtype=int32)>
>>>
Als nächstes möchte ich ein Klassifizierungsproblem mit mnist-Daten machen.
sample1.py
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data() #Daten lesen
x_train, x_test = x_train / 255.0, x_test / 255.0 #Datennormalisierung
#Ein Modell bauen
# Sequential API
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
# optimizer, loss,Metrikeinstellungen (Lerneinstellungen)
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
#Lernen
model.fit(x_train, y_train, epochs=5)
#Auswertung
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print('\nTest accuracy:', test_acc)
Ich denke, es ist ein Schreibstil, den man oft sieht. Dieses Modell modifiziert ein Bild mit 28x28 Eingabe in ein eindimensionales Array 784 unter Verwendung von "Flatten ()". Verbinden Sie danach die vollständig verbundenen Ebenen, und die letzte vollständig verbundene Ebene "10" ist die Anzahl der Klassen (die Anzahl, die Sie klassifizieren möchten). Insbesondere am Ende können Sie die Wahrscheinlichkeit jeder Klasse ermitteln, indem Sie "softmax" als Aktivierung angeben. Zum Lernen und Auswerten können Sie "model.fit", "model.evaluate", "model.predict" usw. verwenden.
Der grundlegende Ablauf besteht darin, (1) Daten zu lesen, (2) Daten vorzuverarbeiten, (3) ein Modell zu erstellen, (4) detaillierte Lerneinstellungen zu erstellen, (5) zu lernen und (6) zu bewerten.
Nachdem Sie ein einfaches Modell mit mnist erstellt und gelernt haben, versuchen wir als nächstes, das Lernen zu übertragen. Transferlernen ist die Verwendung von Gewichten, die im Voraus auf einer großen Anzahl von Bildern wie Imagenet gelernt wurden. Es hat den Vorteil, die Lernzeit zu verkürzen und selbst mit einer kleinen Datenmenge eine gewisse Genauigkeit zu erzielen. Es gibt möglicherweise keinen großen Unterschied zwischen Transferlernen und Feinabstimmung, aber beim Transferlernen bleiben die Gewichte der ersten Ebene fest und es werden nur die Ebenen gelernt, die Sie ersetzen oder selbst hinzufügen. Durch die Feinabstimmung wird das Gewicht der ersten Schicht nicht festgelegt und alle Parameter werden neu trainiert.
TensorFlow Transfer Learning verwendet "tf.keras.applicacctions", um das Modell zu laden.
import tensorflow as tf
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
#Eingabe beim Laden des Modells_Bitte Form angeben
# include_top =Bei der Einstellung False wird die Ausgabeebene nicht gelesen.
IMG_SIZE = (224,224,3)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SIZE,
include_top = False,
weights='imagenet')
#Bei der Festlegung des Gewichts des Basismodells
base_model.trainable = False
#Sie können den Rechenaufwand reduzieren, indem Sie Global Average Pooling ohne vollständig verbundene Ebenen verwenden.
GAP_layer = GlobalAveragePooling2D()
#Da es in 10 Klassen eingeteilt ist, ist es 10. Ersetzen Sie dies durch Ihre eigene Aufgabe.
pred_layer = Dense(10, activation='softmax')
model = tf.keras.Sequential([
base_model,
GAP_layer,
pred_layer
])
# model.summary()Bitte überprüfen Sie das Modell unter
Es gibt andere benutzerfreundliche Modelle, siehe Modul: tf.keras.applications.
+α Obwohl es sich um MobileNetV2 handelt, ist dieses Modell ein sehr "leichtes Modell", das auch an Edge-Terminals funktioniert. Es wird eine Technik namens "Depthwise Separable Convolution" verwendet, die die Faltung getrennt in räumlicher Richtung und Kanalrichtung berechnet, oder eine Aktivierung, die den Ausgabewert maximiert, nachdem "ReLU" durch die Aktivierungsfunktion "ReLU6" geleitet wurde. Es ist ein sehr interessantes Modell, das Funktionen verwendet. Wenn Sie interessiert sind, überprüfen Sie es bitte.
Ab TF2 können Sie beim Erstellen von Modellen die Unterklassifizierungs-API verwenden. Jetzt, da Sie ein Modell wie PyTorch erstellen können, werde ich es vorstellen.
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
class Net(Model):
def __init__(self):
super(Net, self).__init__()
self.conv1 = Conv2D(32, 3, activation='relu') #Conv2D(filters, kernel_size, activation)
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu') # Dense(units, activation)
self.d2 = Dense(10, activation='softmax') # Dense(units, activation)
def call(self, x):
x = self.conv1(x)
x = self.flatten(x)
x = self.d1(x)
return self.d2(x)
#Erstellen Sie eine Instanz des Modells
model = Net()
--Definieren der von __init __
verwendeten Ebene
--Conv2D ()
ist Conv2D (Anzahl der Filter, Kernelgröße, Aktivierungsfunktion)
--Flatten ()
konvertiert die Feature-Map in eine Dimension. Beispiel 28x28-> 784
--Dense ()
ist eine vollständig verbundene Ebene. Gibt die Anzahl der Dimensionen im Ausgabebereich an
def call (self, x) fließen:
Informationen zum Modellbau finden Sie unter 4. Erstellen Sie Ihr eigenes Modell.
#Definition der Verlustfunktion
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
#Optimierungseinstellungen
optimizer = tf.keras.optimizers.Adam()
###Wird zur Berechnung von Verlust und Unfall verwendet
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')
def train_step(images, labels):
with tf.GradientTape() as tape: #Führen Sie von nun an einen Verlauf der durchzuführenden Berechnungen
predictions = model(images) #Fügen Sie ein Bild in das Modell ein und erhalten Sie eine Vorhersage
loss = loss_object(labels, predictions) #Berechnen Sie den Verlust anhand der korrekten Bezeichnung und Vorhersage
gradients = tape.gradient(loss, model.trainable_variables) #Differenzieren Sie die Verlustfunktion mit lernbaren Parametern
optimizer.apply_gradients(zip(gradients, model.trainable_variables)) #Mit Verlaufsinformationen aktualisiert
train_loss(loss)
train_accuracy(labels, predictions)
――Differenzierung ist für maschinelles Lernen unbedingt erforderlich
tf.GradientTape
, wo Sie den Berechnungsverlauf behalten möchtentf.GradientTape
ist eine Klasse zum Finden des Gradienten.import tensorflow as tf
x = tf.constant(3.0)
with tf.GradientTape() as tape:
tape.watch(x)
y = 3x+2
gradient = tape.gradient(y,x)
print(f'y = {y}')
print(f'x = {x}')
print(f'grad = {gradient}')
Output
y = 11.0
x = 3.0
grad = 3.0
Schließlich habe ich den Code für meinen Zug und Val gepostet. Es ist voll von Tsukkomi-Orten, aber bitte verwenden Sie es als Referenz.
def train(model, train_dataset, loss_object, optimizer, train_loss, train_acc, CONFIG, train_count):
cnt = 0
max_value = train_count + CONFIG.batch_size
with progressbar.ProgressBar(max_value=max_value) as bar:
for imgs, labels in train_dataset:
with tf.GradientTape() as tape:
preds = model(imgs, training=True)
loss = loss_object(labels, preds)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
train_loss.update_state(values=loss)
train_acc.update_state(labels, preds)
cnt = cnt + CONFIG.batch_size
bar.update(cnt)
loss_t = train_loss.result().numpy()
acc_t = train_acc.result().numpy()
train_loss.reset_states()
train_acc.reset_states()
return loss_t, acc_t
def val(model, val_dataset, loss_object,optimizer, val_loss, val_acc,CONFIG, val_count):
cnt = 0
max_value = val_count + CONFIG.batch_size
with progressbar.ProgressBar(max_value=max_value) as bar:
for imgs, labels in val_dataset:
preds = model(imgs, training=False)
loss = loss_object(labels, preds)
val_loss.update_state(values=loss)
val_acc.update_state(labels, preds)
cnt = cnt + CONFIG.batch_size
bar.update(cnt)
loss_v = val_loss.result().numpy()
acc_v = val_acc.result().numpy()
val_loss.reset_states()
val_acc.reset_states()
return loss_v, acc_v
-- tqdm
funktioniert in meiner Umgebung nicht gut und ich verwende progressbar
--acc und loss werden mit .update_state ()
aktualisiert
--acc- und Verlustmetriken müssen in jeder Epoche zurückgesetzt werden, also mit .reset_states ()
zurücksetzen
Wenn Sie mit Ihrem eigenen Datensatz lernen, gibt es meiner Meinung nach zwei Haupttypen.
--Verwenden Sie flow_from_directory ()
--Einstellungen wie target_size, batch_size, class_mode sind erforderlich
train_aug = ImageDataGenerator(
rescale=(1./255),
horizontal_flip=True,
vertical_flip=True,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
rotation_range=30,
)
test_aug = ImageDataGenerator(
rescale=(1./255),
)
train_generator = train_aug.flow_from_directory(
'data/train',
target_size=(224,224),
batch_size=batch_size,
class_mode='categorical'
)
test_generator = test_aug.flow_from_directory(
'data/val',
target_size=(224,224),
batch_size=batch_size,
class_mode='categorical'
)
Wenn Sie den Bildpfad und die Beschriftung nach CSV exportieren und laden möchten, wird diese Methode meiner Meinung nach häufig verwendet. Ich denke, dass jede Bibliothek beim Laden von Bildern funktioniert. Im Folgenden schreibe ich, bis ich den Dateipfad des Bildes erhalte und daraus einen Datensatz erstelle.
import os
import pathlib
import tensorflow as tf
#Datenpfadspezifikation
data_root_dir = 'data/train'
data_root = pathlib.Path(data_root_dir)
#Bildpfad abrufen
all_image_paths = [str(path) for path in list(data_root.glob('*/*'))]
#Sortieren
all_image_paths = sorted(all_image_paths)
#Bestätigung
print(all_image_paths)
print(len(all_image_paths))
#Holen Sie sich das Etikett:Vom Verzeichnisnamen abrufen
label_names = sorted(item.name for item in data_root.glob('*/'))
print(f' label : {label_names}')
#Diktat zur Erstellung des Etikettenwörterbuchs{label:index}
label_to_index = dict((label, index) for index, label in enumerate(label_names))
print(label_to_index)
#Beschriftungen für alle Bilder erhalten
all_image_labels = [label_to_index[pathlib.Path(image_path).parent.name] for image_path in all_image_paths]
print(all_image_labels)
def load_data(all_image_paths, all_image_labels):
img_list = []
for filename in all_image_paths:
#Laden von Bildern
img = tf.io.read_file(filename)
#Dekodieren
img = tf.io.decode_image(img,channels = 3)
#Wenn Sie die Größe oder Größe nicht ändern, tritt beim Erstellen eines Datasets ein Fehler auf.
img = tf.image.resize(img, [224,224])
img_list.append(img)
images = tf.stack(img_list, axis=0)
labels = tf.stack(all_image_labels, axis=0)
return tf.cast(images, tf.float32), tf.cast(labels, tf.int32)
#Holen Sie sich Bild und Etikett
imgs, labels = load_data(all_image_paths, all_image_labels)
#Mische Daten, um Stapel zu erstellen
dataset = tf.data.Dataset.from_tensor_slices((img_list, label_list)).shuffle(len(all_image_labels)).batch(8)
#Bestätigung
for data1, data2 in dataset.take(10):
print(data1, data2)
tf.data.Dataset.from_tensor_slices ()
erstellen
--Verwenden Sie shuffle ()
, wenn Sie Ihren Datensatz mischen möchten
--Verwenden Sie batch ()
, wenn Sie nach Batch gruppieren möchten
--Bitte beachten Sie, dass sich das Verhalten ändert, wenn die Reihenfolge von "Mischen" und "Stapeln" umgekehrt wird.[2]. Augmentaion
image = tf.io.decode_image(contents=image,
channels=CONFIG.channels,
dtype=tf.dtypes.float32)
#Normalisierung
image = (image / 0.5) -1
# data_aug =Wenn wahr
if data_aug:
image = tf.image.random_flip_left_right(image=image)
image = tf.image.resize_with_crop_or_pad(image=image,
target_height=int(CONFIG.img_height*1.2),
target_width=int(CONFIG.img_width*1.2))
image = tf.image.random_crop(value=image, size=[CONFIG.img_height,CONFIG.img_width, CONFIG.channels])
else:
image = tf.image.resize(image_tensor, [CONFIG.img_height, CONFIG.img_width])
[3]. TensorBoard
import tensorflow as tf
#Geben Sie den Spuckort des Protokolls an
writer = tf.summary.create_file_writer('tmp/mylogs')
with writer.as_default():
for step in range(100):
tf.summary.scalar("acc/train", 0.7, step=step)
tf.summary.scalar("acc/val", 0.5, step=step)
tf.summary.scalar("loss/train", 0.7, step=step)
tf.summary.scalar("loss/val", 0.5, step=step)
writer.flush()
--Schreiben Sie in Form von "tf.summary.scalar (Tag, Wert, Schritt)" ――In diesem Beispiel wird es durch eine Konstante wie 0,5 oder 0,7 angegeben, aber Sie können den tatsächlichen Verlust oder gem. ―― Zusätzlich zu den Werten können Sie auch Bilder erstellen. Probieren Sie daher verschiedene Dinge aus.
Geben Sie bei der Überprüfung das Verzeichnis des Spuckprotokolls wie folgt an und greifen Sie auf "http: // localhost: 6006 /" zu
$ tensorboard --logdir='./tmp/mylogs'
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
TensorBoard 2.1.1 at http://localhost:6006/ (Press CTRL+C to quit)
[4]. TFRecord
--TFRecord ist eine binäre Version der Daten in dem von TensorFlow empfohlenen Format.
def _bytes_feature(value):
if isinstance(value, type(tf.constant(0.))):
value = value.numpy()
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def _float_feature(value):
return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
def _int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def get_info(data_root_dir):
data_root = pathlib.Path(data_root_dir)
all_image_paths = [str(path) for path in list(data_root.glob('*/*'))]
# Get label
label_names = sorted(item.name for item in data_root.glob('*/'))
# dict {label:index}
label_to_index = dict((label, index) for index, label in enumerate(label_names))
print(label_to_index)
# Get all images label
all_image_labels = [label_to_index[pathlib.Path(image_path).parent.name] for image_path in all_image_paths]
return all_image_paths, all_image_labels
def dataset_to_tfrecord(dataset_dir, tfrecord_name):
#Holen Sie sich Bilder und Beschriftungen für jedes Verzeichnis
image_paths, image_labels = get_info(dataset_dir)
image_paths_and_labels_dict = {}
#In Wörterbuchtyp konvertieren
for i in range(len(image_paths)):
image_paths_and_labels_dict[image_paths[i]] = image_labels[i]
with tf.io.TFRecordWriter(path=tfrecord_name) as writer:
for image_path, label in image_paths_and_labels_dict.items():
image_string = open(image_path, 'rb').read()
feature = {
'label' : _int64_feature(label),
'image' : _bytes_feature(image_string)
}
tf_example = tf.train.Example(features=tf.train.Features(feature=feature))
writer.write(tf_example.SerializeToString())
Weitere Informationen finden Sie unter TensorFLow TFRecord und tf.Example.
Wir haben gesehen, wie man Bilder mit TensorFLow klassifiziert. Die "Sitzung" und der "Platzhalter", die sich in TF1 befanden, sind verschwunden, der "Eager-Modus" wurde standardmäßig aktiviert, und Keras wurde zu einer API auf hoher Ebene des TensorFLow-Standards, was die persönliche Verwendung vereinfacht. War dort. Es ist schwer, sich daran zu gewöhnen, aber als ich mich daran gewöhnt hatte, war TensorFLow einfach zu schreiben. In Zukunft möchte ich sowohl Pytorch als auch TensorFlow beherrschen können. Es gibt viele nützliche Bibliotheken wie ** pathlib ** und ** albumentaions **, die in der Mitte des Artikels vorgestellt wurden. Wenn Sie sie also nicht verwenden, verwenden Sie sie bitte.
Recommended Posts