![]() | ![]() | ![]() | ![]() |
Kurulum
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
Giriş
Keras işlevsel API'si , tf.keras.Sequential
API'sinden daha esnek modeller oluşturmanın bir yoludur. İşlevsel API, doğrusal olmayan topolojiye, paylaşılan katmanlara ve hatta birden çok giriş veya çıkışa sahip modelleri işleyebilir.
Ana fikir, derin öğrenme modelinin genellikle katmanların yönlendirilmiş döngüsel olmayan grafiği (DAG) olmasıdır. Dolayısıyla işlevsel API, katman grafikleri oluşturmanın bir yoludur.
Aşağıdaki modeli düşünün:
(input: 784-dimensional vectors)
↧
[Dense (64 units, relu activation)]
↧
[Dense (64 units, relu activation)]
↧
[Dense (10 units, softmax activation)]
↧
(output: logits of a probability distribution over 10 classes)
Bu, üç katmanlı temel bir grafiktir. Bu modeli işlevsel API kullanarak oluşturmak için bir giriş düğümü oluşturarak başlayın:
inputs = keras.Input(shape=(784,))
Verilerin şekli 784 boyutlu bir vektör olarak belirlendi. Her numunenin yalnızca şekli belirtildiğinden parti boyutu her zaman ihmal edilir.
Örneğin, (32, 32, 3)
şeklinde bir görüntü girişiniz varsa, şunu kullanırsınız:
# Just for demonstration purposes.
img_inputs = keras.Input(shape=(32, 32, 3))
Döndürülen inputs
, modelinize beslediğiniz girdi verilerinin şekli ve dtype
hakkında bilgi içerir. İşte şekil:
inputs.shape
TensorShape([None, 784])
İşte dtype:
inputs.dtype
tf.float32
Bu inputs
nesnesinde bir katman çağırarak katman grafiğinde yeni bir düğüm oluşturursunuz:
dense = layers.Dense(64, activation="relu")
x = dense(inputs)
"Katman çağrısı" eylemi, "girdilerden" oluşturduğunuz bu katmana bir ok çizmek gibidir. Girdileri dense
katmana "geçiriyorsunuz" ve çıktı olarak x
elde ediyorsunuz.
Katman grafiğine birkaç katman daha ekleyelim:
x = layers.Dense(64, activation="relu")(x)
outputs = layers.Dense(10)(x)
Bu noktada, giriş ve çıkışlarını katman grafiğinde belirterek bir Model
oluşturabilirsiniz:
model = keras.Model(inputs=inputs, outputs=outputs, name="mnist_model")
Model özetinin neye benzediğine bakalım:
model.summary()
Model: "mnist_model" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) [(None, 784)] 0 _________________________________________________________________ dense (Dense) (None, 64) 50240 _________________________________________________________________ dense_1 (Dense) (None, 64) 4160 _________________________________________________________________ dense_2 (Dense) (None, 10) 650 ================================================================= Total params: 55,050 Trainable params: 55,050 Non-trainable params: 0 _________________________________________________________________
Modeli grafik olarak da çizebilirsiniz:
keras.utils.plot_model(model, "my_first_model.png")
Ve isteğe bağlı olarak, çizilen grafikte her katmanın giriş ve çıkış şekillerini görüntüleyin:
keras.utils.plot_model(model, "my_first_model_with_shape_info.png", show_shapes=True)
Bu rakam ve kod hemen hemen aynı. Kod versiyonunda, bağlantı oklarının yerini arama işlemi alır.
Bir "katman grafiği", bir derin öğrenme modeli için sezgisel bir zihinsel görüntüdür ve işlevsel API, bunu yakından yansıtan modeller oluşturmanın bir yoludur.
Eğitim, değerlendirme ve çıkarım
Eğitim, değerlendirme ve çıkarım, Sequential
modellerde olduğu gibi işlevsel API kullanılarak oluşturulan modeller için tam olarak aynı şekilde çalışır.
Model
sınıfı, yerleşik bir eğitim döngüsü ( fit()
yöntemi) ve yerleşik bir değerlendirme döngüsü ( evaluate()
yöntemi) sunar. Denetimli öğrenmenin ötesinde eğitim rutinlerini uygulamak için bu döngüleri kolayca özelleştirebileceğinizi unutmayın (örn. GAN'lar ).
Burada, MNIST görüntü verilerini yükleyin, vektörler halinde yeniden şekillendirin, modeli verilere uydurun (bir doğrulama bölümünde performansı izlerken), ardından modeli test verileri üzerinde değerlendirin:
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype("float32") / 255
x_test = x_test.reshape(10000, 784).astype("float32") / 255
model.compile(
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer=keras.optimizers.RMSprop(),
metrics=["accuracy"],
)
history = model.fit(x_train, y_train, batch_size=64, epochs=2, validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=2)
print("Test loss:", test_scores[0])
print("Test accuracy:", test_scores[1])
Epoch 1/2 750/750 [==============================] - 3s 3ms/step - loss: 0.5848 - accuracy: 0.8332 - val_loss: 0.1880 - val_accuracy: 0.9480 Epoch 2/2 750/750 [==============================] - 2s 2ms/step - loss: 0.1699 - accuracy: 0.9503 - val_loss: 0.1490 - val_accuracy: 0.9563 313/313 - 0s - loss: 0.1463 - accuracy: 0.9563 Test loss: 0.14626088738441467 Test accuracy: 0.9563000202178955
Daha fazla okuma için eğitim ve değerlendirme kılavuzuna bakın.
Kaydet ve serileştir
Model ve serileştirmenin kaydedilmesi, Sequential
modellerde olduğu gibi, işlevsel API kullanılarak oluşturulan modeller için de aynı şekilde çalışır. İşlevsel bir modeli kaydetmenin standart yolu, tüm modeli tek bir dosya olarak kaydetmek için model.save()
yi çağırmaktır. Modeli oluşturan kod artık mevcut olmasa bile, aynı modeli daha sonra bu dosyadan yeniden oluşturabilirsiniz.
Kaydedilen bu dosya şunları içerir:
- model mimarisi
- model ağırlık değerleri (eğitim sırasında öğrenilenler)
- varsa model eğitim yapılandırması (
compile
geçildiği gibi) - optimizer ve varsa durumu (eğitimi kaldığınız yerden yeniden başlatmak için)
model.save("path_to_my_model")
del model
# Recreate the exact same model purely from the file:
model = keras.models.load_model("path_to_my_model")
INFO:tensorflow:Assets written to: path_to_my_model/assets
Ayrıntılar için model serileştirme ve kaydetme kılavuzunu okuyun.
Birden çok modeli tanımlamak için aynı katman grafiğini kullanın
İşlevsel API'de modeller, bir katman grafiğinde girdileri ve çıktıları belirtilerek oluşturulur. Bu, birden çok model oluşturmak için tek bir katman grafiğinin kullanılabileceği anlamına gelir.
Aşağıdaki örnekte, iki modeli somutlaştırmak için aynı katman yığınını kullanacaksınız: görüntü girişlerini 16 boyutlu vektörlere dönüştüren bir encoder
modeli ve eğitim için uçtan uca bir autoencoder
modeli.
encoder_input = keras.Input(shape=(28, 28, 1), name="img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name="encoder")
encoder.summary()
x = layers.Reshape((4, 4, 1))(encoder_output)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
x = layers.Conv2DTranspose(32, 3, activation="relu")(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation="relu")(x)
autoencoder = keras.Model(encoder_input, decoder_output, name="autoencoder")
autoencoder.summary()
Model: "encoder" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= img (InputLayer) [(None, 28, 28, 1)] 0 _________________________________________________________________ conv2d (Conv2D) (None, 26, 26, 16) 160 _________________________________________________________________ conv2d_1 (Conv2D) (None, 24, 24, 32) 4640 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 8, 8, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 6, 6, 32) 9248 _________________________________________________________________ conv2d_3 (Conv2D) (None, 4, 4, 16) 4624 _________________________________________________________________ global_max_pooling2d (Global (None, 16) 0 ================================================================= Total params: 18,672 Trainable params: 18,672 Non-trainable params: 0 _________________________________________________________________ Model: "autoencoder" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= img (InputLayer) [(None, 28, 28, 1)] 0 _________________________________________________________________ conv2d (Conv2D) (None, 26, 26, 16) 160 _________________________________________________________________ conv2d_1 (Conv2D) (None, 24, 24, 32) 4640 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 8, 8, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 6, 6, 32) 9248 _________________________________________________________________ conv2d_3 (Conv2D) (None, 4, 4, 16) 4624 _________________________________________________________________ global_max_pooling2d (Global (None, 16) 0 _________________________________________________________________ reshape (Reshape) (None, 4, 4, 1) 0 _________________________________________________________________ conv2d_transpose (Conv2DTran (None, 6, 6, 16) 160 _________________________________________________________________ conv2d_transpose_1 (Conv2DTr (None, 8, 8, 32) 4640 _________________________________________________________________ up_sampling2d (UpSampling2D) (None, 24, 24, 32) 0 _________________________________________________________________ conv2d_transpose_2 (Conv2DTr (None, 26, 26, 16) 4624 _________________________________________________________________ conv2d_transpose_3 (Conv2DTr (None, 28, 28, 1) 145 ================================================================= Total params: 28,241 Trainable params: 28,241 Non-trainable params: 0 _________________________________________________________________
Burada, kod çözme mimarisi, kodlama mimarisine kesinlikle simetriktir, bu nedenle çıktı şekli, giriş şekli (28, 28, 1)
aynıdır.
Bir ters Conv2D
tabakası a, Conv2DTranspose
tabakası ve bir arka MaxPooling2D
tabakası bir olduğunu UpSampling2D
katmanı.
Katmanlar gibi tüm modeller çağrılabilir
Herhangi bir modeli bir Input
veya başka bir katmanın çıktısında çağırarak bir katmanmış gibi ele alabilirsiniz. Bir modeli çağırarak, sadece modelin mimarisini yeniden kullanmakla kalmaz, aynı zamanda ağırlıklarını da yeniden kullanırsınız.
Bunu iş başında görmek için, bir kodlayıcı modeli, bir kod çözücü modeli oluşturan ve bunları otomatik kodlayıcı modelini elde etmek için iki çağrıda zincirleyen otomatik kodlayıcı örneğinin farklı bir yaklaşımını burada bulabilirsiniz:
encoder_input = keras.Input(shape=(28, 28, 1), name="original_img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name="encoder")
encoder.summary()
decoder_input = keras.Input(shape=(16,), name="encoded_img")
x = layers.Reshape((4, 4, 1))(decoder_input)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
x = layers.Conv2DTranspose(32, 3, activation="relu")(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation="relu")(x)
decoder = keras.Model(decoder_input, decoder_output, name="decoder")
decoder.summary()
autoencoder_input = keras.Input(shape=(28, 28, 1), name="img")
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name="autoencoder")
autoencoder.summary()
Model: "encoder" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= original_img (InputLayer) [(None, 28, 28, 1)] 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 26, 26, 16) 160 _________________________________________________________________ conv2d_5 (Conv2D) (None, 24, 24, 32) 4640 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 8, 8, 32) 0 _________________________________________________________________ conv2d_6 (Conv2D) (None, 6, 6, 32) 9248 _________________________________________________________________ conv2d_7 (Conv2D) (None, 4, 4, 16) 4624 _________________________________________________________________ global_max_pooling2d_1 (Glob (None, 16) 0 ================================================================= Total params: 18,672 Trainable params: 18,672 Non-trainable params: 0 _________________________________________________________________ Model: "decoder" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= encoded_img (InputLayer) [(None, 16)] 0 _________________________________________________________________ reshape_1 (Reshape) (None, 4, 4, 1) 0 _________________________________________________________________ conv2d_transpose_4 (Conv2DTr (None, 6, 6, 16) 160 _________________________________________________________________ conv2d_transpose_5 (Conv2DTr (None, 8, 8, 32) 4640 _________________________________________________________________ up_sampling2d_1 (UpSampling2 (None, 24, 24, 32) 0 _________________________________________________________________ conv2d_transpose_6 (Conv2DTr (None, 26, 26, 16) 4624 _________________________________________________________________ conv2d_transpose_7 (Conv2DTr (None, 28, 28, 1) 145 ================================================================= Total params: 9,569 Trainable params: 9,569 Non-trainable params: 0 _________________________________________________________________ Model: "autoencoder" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= img (InputLayer) [(None, 28, 28, 1)] 0 _________________________________________________________________ encoder (Functional) (None, 16) 18672 _________________________________________________________________ decoder (Functional) (None, 28, 28, 1) 9569 ================================================================= Total params: 28,241 Trainable params: 28,241 Non-trainable params: 0 _________________________________________________________________
Gördüğünüz gibi, model yuvalanabilir: bir model alt modeller içerebilir (çünkü bir model tıpkı bir katman gibidir). Model yerleştirme için yaygın bir kullanım durumu, bir araya getirmedir . Örneğin, bir dizi modeli, tahminlerinin ortalamasını alan tek bir modelde nasıl birleştireceğiniz aşağıda açıklanmıştır:
def get_model():
inputs = keras.Input(shape=(128,))
outputs = layers.Dense(1)(inputs)
return keras.Model(inputs, outputs)
model1 = get_model()
model2 = get_model()
model3 = get_model()
inputs = keras.Input(shape=(128,))
y1 = model1(inputs)
y2 = model2(inputs)
y3 = model3(inputs)
outputs = layers.average([y1, y2, y3])
ensemble_model = keras.Model(inputs=inputs, outputs=outputs)
Karmaşık grafik topolojilerini işleyin
Birden çok giriş ve çıkışa sahip modeller
İşlevsel API, birden çok giriş ve çıkışın değiştirilmesini kolaylaştırır. Bu, Sequential
API ile ele alınamaz.
Örneğin, müşteri çıkış biletlerini önceliğe göre sıralamak ve bunları doğru departmana yönlendirmek için bir sistem oluşturuyorsanız, modelin üç girdisi olacaktır:
- biletin başlığı (metin girişi),
- biletin metin gövdesi (metin girişi) ve
- kullanıcı tarafından eklenen herhangi bir etiket (kategorik girdi)
Bu modelin iki çıktısı olacaktır:
- 0 ile 1 arasındaki öncelik puanı (skaler sigmoid çıktı) ve
- bileti işlemesi gereken departman (departmanlar kümesi üzerinden softmax çıktısı).
Bu modeli, işlevsel API ile birkaç satırda oluşturabilirsiniz:
num_tags = 12 # Number of unique issue tags
num_words = 10000 # Size of vocabulary obtained when preprocessing text data
num_departments = 4 # Number of departments for predictions
title_input = keras.Input(
shape=(None,), name="title"
) # Variable-length sequence of ints
body_input = keras.Input(shape=(None,), name="body") # Variable-length sequence of ints
tags_input = keras.Input(
shape=(num_tags,), name="tags"
) # Binary vectors of size `num_tags`
# Embed each word in the title into a 64-dimensional vector
title_features = layers.Embedding(num_words, 64)(title_input)
# Embed each word in the text into a 64-dimensional vector
body_features = layers.Embedding(num_words, 64)(body_input)
# Reduce sequence of embedded words in the title into a single 128-dimensional vector
title_features = layers.LSTM(128)(title_features)
# Reduce sequence of embedded words in the body into a single 32-dimensional vector
body_features = layers.LSTM(32)(body_features)
# Merge all available features into a single large vector via concatenation
x = layers.concatenate([title_features, body_features, tags_input])
# Stick a logistic regression for priority prediction on top of the features
priority_pred = layers.Dense(1, name="priority")(x)
# Stick a department classifier on top of the features
department_pred = layers.Dense(num_departments, name="department")(x)
# Instantiate an end-to-end model predicting both priority and department
model = keras.Model(
inputs=[title_input, body_input, tags_input],
outputs=[priority_pred, department_pred],
)
Şimdi modeli çizin:
keras.utils.plot_model(model, "multi_input_and_output_model.png", show_shapes=True)
Bu modeli derlerken, her çıktıya farklı kayıplar atayabilirsiniz. Toplam eğitim kaybına katkılarını düzenlemek için her bir kayba farklı ağırlıklar bile atayabilirsiniz.
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=[
keras.losses.BinaryCrossentropy(from_logits=True),
keras.losses.CategoricalCrossentropy(from_logits=True),
],
loss_weights=[1.0, 0.2],
)
Çıktı katmanlarının farklı adları olduğundan, kaybı şu şekilde de belirtebilirsiniz:
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={
"priority": keras.losses.BinaryCrossentropy(from_logits=True),
"department": keras.losses.CategoricalCrossentropy(from_logits=True),
},
loss_weights=[1.0, 0.2],
)
NumPy giriş ve hedef dizilerinin listelerini ileterek modeli eğitin:
# Dummy input data
title_data = np.random.randint(num_words, size=(1280, 10))
body_data = np.random.randint(num_words, size=(1280, 100))
tags_data = np.random.randint(2, size=(1280, num_tags)).astype("float32")
# Dummy target data
priority_targets = np.random.random(size=(1280, 1))
dept_targets = np.random.randint(2, size=(1280, num_departments))
model.fit(
{"title": title_data, "body": body_data, "tags": tags_data},
{"priority": priority_targets, "department": dept_targets},
epochs=2,
batch_size=32,
)
Epoch 1/2 40/40 [==============================] - 4s 11ms/step - loss: 1.2978 - priority_loss: 0.7067 - department_loss: 2.9554 Epoch 2/2 40/40 [==============================] - 0s 11ms/step - loss: 1.2947 - priority_loss: 0.7023 - department_loss: 2.9621 <tensorflow.python.keras.callbacks.History at 0x7fe18923e6a0>
Bir Dataset
nesnesiyle fit ([title_data, body_data, tags_data], [priority_targets, dept_targets])
ya ([title_data, body_data, tags_data], [priority_targets, dept_targets])
gibi bir ([title_data, body_data, tags_data], [priority_targets, dept_targets])
demeti veya ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets})
.
Daha ayrıntılı açıklama için eğitim ve değerlendirme kılavuzuna bakın.
Bir oyuncak ResNet modeli
Birden çok giriş ve çıkışa sahip modellere ek olarak, işlevsel API, doğrusal olmayan bağlantı topolojilerini yönetmeyi kolaylaştırır - bunlar, Sequential
API'nin işleyemediği, Sequential
bağlanmayan katmanlara sahip modellerdir.
Bunun için yaygın bir kullanım durumu, artık bağlantılardır. Bunu göstermek için CIFAR10 için bir oyuncak ResNet modeli oluşturalım:
inputs = keras.Input(shape=(32, 32, 3), name="img")
x = layers.Conv2D(32, 3, activation="relu")(inputs)
x = layers.Conv2D(64, 3, activation="relu")(x)
block_1_output = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_1_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_2_output = layers.add([x, block_1_output])
x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_2_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_3_output = layers.add([x, block_2_output])
x = layers.Conv2D(64, 3, activation="relu")(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10)(x)
model = keras.Model(inputs, outputs, name="toy_resnet")
model.summary()
Model: "toy_resnet" __________________________________________________________________________________________________ Layer (type) Output Shape Param # Connected to ================================================================================================== img (InputLayer) [(None, 32, 32, 3)] 0 __________________________________________________________________________________________________ conv2d_8 (Conv2D) (None, 30, 30, 32) 896 img[0][0] __________________________________________________________________________________________________ conv2d_9 (Conv2D) (None, 28, 28, 64) 18496 conv2d_8[0][0] __________________________________________________________________________________________________ max_pooling2d_2 (MaxPooling2D) (None, 9, 9, 64) 0 conv2d_9[0][0] __________________________________________________________________________________________________ conv2d_10 (Conv2D) (None, 9, 9, 64) 36928 max_pooling2d_2[0][0] __________________________________________________________________________________________________ conv2d_11 (Conv2D) (None, 9, 9, 64) 36928 conv2d_10[0][0] __________________________________________________________________________________________________ add (Add) (None, 9, 9, 64) 0 conv2d_11[0][0] max_pooling2d_2[0][0] __________________________________________________________________________________________________ conv2d_12 (Conv2D) (None, 9, 9, 64) 36928 add[0][0] __________________________________________________________________________________________________ conv2d_13 (Conv2D) (None, 9, 9, 64) 36928 conv2d_12[0][0] __________________________________________________________________________________________________ add_1 (Add) (None, 9, 9, 64) 0 conv2d_13[0][0] add[0][0] __________________________________________________________________________________________________ conv2d_14 (Conv2D) (None, 7, 7, 64) 36928 add_1[0][0] __________________________________________________________________________________________________ global_average_pooling2d (Globa (None, 64) 0 conv2d_14[0][0] __________________________________________________________________________________________________ dense_6 (Dense) (None, 256) 16640 global_average_pooling2d[0][0] __________________________________________________________________________________________________ dropout (Dropout) (None, 256) 0 dense_6[0][0] __________________________________________________________________________________________________ dense_7 (Dense) (None, 10) 2570 dropout[0][0] ================================================================================================== Total params: 223,242 Trainable params: 223,242 Non-trainable params: 0 __________________________________________________________________________________________________
Modeli çizin:
keras.utils.plot_model(model, "mini_resnet.png", show_shapes=True)
Şimdi modeli eğitin:
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=["acc"],
)
# We restrict the data to the first 1000 samples so as to limit execution time
# on Colab. Try to train on the entire dataset until convergence!
model.fit(x_train[:1000], y_train[:1000], batch_size=64, epochs=1, validation_split=0.2)
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170500096/170498071 [==============================] - 6s 0us/step 13/13 [==============================] - 2s 35ms/step - loss: 2.2992 - acc: 0.1273 - val_loss: 2.2629 - val_acc: 0.1850 <tensorflow.python.keras.callbacks.History at 0x7fe210396ef0>
Paylaşılan katmanlar
İşlevsel API'nin bir başka iyi kullanımı, paylaşılan katmanları kullanan modellerdir. Paylaşılan katmanlar, aynı modelde birden çok kez yeniden kullanılan katman örnekleridir - katman grafiğindeki birden çok yola karşılık gelen özellikleri öğrenirler.
Paylaşılan katmanlar genellikle benzer alanlardan gelen girdileri kodlamak için kullanılır (örneğin, benzer kelime dağarcığı içeren iki farklı metin parçası). Bu farklı girdiler arasında bilgi paylaşımını sağlarlar ve böyle bir modeli daha az veriyle eğitmeyi mümkün kılarlar. Girişlerden birinde belirli bir kelime görülürse, bu, paylaşılan katmandan geçen tüm girişlerin işlenmesine fayda sağlayacaktır.
İşlevsel API'de bir katmanı paylaşmak için aynı katman örneğini birden çok kez çağırın. Örneğin, iki farklı metin girişi arasında paylaşılan bir Embedding
katmanı aşağıda verilmiştir:
# Embedding for 1000 unique words mapped to 128-dimensional vectors
shared_embedding = layers.Embedding(1000, 128)
# Variable-length sequence of integers
text_input_a = keras.Input(shape=(None,), dtype="int32")
# Variable-length sequence of integers
text_input_b = keras.Input(shape=(None,), dtype="int32")
# Reuse the same layer to encode both inputs
encoded_input_a = shared_embedding(text_input_a)
encoded_input_b = shared_embedding(text_input_b)
Katman grafiğindeki düğümleri ayıklayın ve yeniden kullanın
İşlemekte olduğunuz katmanların grafiği statik bir veri yapısı olduğu için erişilebilir ve incelenebilir. Ve bu, işlevsel modelleri görüntü olarak nasıl çizebildiğinizdir.
Bu ayrıca, ara katmanların (grafikteki "düğümler") etkinleştirmelerine erişebileceğiniz ve bunları başka yerlerde yeniden kullanabileceğiniz anlamına gelir - bu, özellik çıkarma gibi bir şey için çok yararlıdır.
Bir örneğe bakalım. Bu, ağırlıkları ImageNet üzerinde önceden eğitilmiş bir VGG19 modelidir:
vgg19 = tf.keras.applications.VGG19()
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg19/vgg19_weights_tf_dim_ordering_tf_kernels.h5 574717952/574710816 [==============================] - 7s 0us/step
Ve bunlar, grafik veri yapısının sorgulanmasıyla elde edilen modelin ara etkinleştirmeleridir:
features_list = [layer.output for layer in vgg19.layers]
Ara katman etkinleştirmelerinin değerlerini döndüren yeni bir özellik çıkarma modeli oluşturmak için şu özellikleri kullanın:
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)
img = np.random.random((1, 224, 224, 3)).astype("float32")
extracted_features = feat_extraction_model(img)
Bu, diğer şeylerin yanı sıra sinir stili aktarımı gibi görevler için kullanışlıdır.
API'yi özel katmanlar kullanarak genişletin
tf.keras
çok çeşitli yerleşik katmanlar içerir, örneğin:
-
Conv1D
katmanlar:Conv1D
,Conv2D
,Conv3D
,Conv2DTranspose
-
MaxPooling1D
katmanları:MaxPooling1D
,MaxPooling2D
,MaxPooling3D
,AveragePooling1D
- RNN katmanları:
GRU
,LSTM
,ConvLSTM2D
-
BatchNormalization
,Dropout
,Embedding
vb
Ancak ihtiyacınız olanı bulamazsanız, kendi katmanlarınızı oluşturarak API'yi genişletmek kolaydır. Tüm katmanlar, Layer
sınıfını alt sınıflandırır ve uygular:
- katman tarafından yapılan hesaplamayı belirten
call
yöntemi. - Katmanın ağırlıklarını oluşturan
build
yöntemi (__init__
içinde de ağırlık oluşturabileceğiniz için bu sadece bir stil__init__
).
Sıfırdan katman oluşturma hakkında daha fazla bilgi edinmek için özel katmanlar ve modeller kılavuzunu okuyun.
Aşağıda tf.keras.layers.Dense
için temel bir uygulama yer tf.keras.layers.Dense
:
class CustomDense(layers.Layer):
def __init__(self, units=32):
super(CustomDense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(
shape=(input_shape[-1], self.units),
initializer="random_normal",
trainable=True,
)
self.b = self.add_weight(
shape=(self.units,), initializer="random_normal", trainable=True
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)
model = keras.Model(inputs, outputs)
Özel katmanınızda serileştirme desteği için, katman örneğinin yapıcı argümanlarını döndüren bir get_config
yöntemi tanımlayın:
class CustomDense(layers.Layer):
def __init__(self, units=32):
super(CustomDense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(
shape=(input_shape[-1], self.units),
initializer="random_normal",
trainable=True,
)
self.b = self.add_weight(
shape=(self.units,), initializer="random_normal", trainable=True
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
def get_config(self):
return {"units": self.units}
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)
model = keras.Model(inputs, outputs)
config = model.get_config()
new_model = keras.Model.from_config(config, custom_objects={"CustomDense": CustomDense})
İsteğe bağlı olarak, yapılandırma sözlüğü verilen bir katman örneğini yeniden oluştururken kullanılan from_config(cls, config)
sınıf yöntemini from_config(cls, config)
. from_config
varsayılan uygulaması şudur:
def from_config(cls, config):
return cls(**config)
İşlevsel API ne zaman kullanılır?
Yeni bir model oluşturmak için Keras işlevsel API'sini mi kullanmalısınız yoksa doğrudan Model
sınıfını alt sınıflara mı ayırmalısınız? Genel olarak, işlevsel API daha yüksek seviyeli, daha kolay ve daha güvenlidir ve alt sınıflı modellerin desteklemediği bir dizi özelliğe sahiptir.
Bununla birlikte, model alt sınıflandırma, katmanların yönlendirilmiş döngüsel olmayan grafikleri olarak kolayca ifade edilemeyen modeller oluştururken daha fazla esneklik sağlar. Örneğin, işlevsel API ile bir Tree-RNN uygulayamazsınız ve Model
doğrudan alt sınıflara ayırmanız gerekir.
İşlevsel API ve model alt sınıflandırma arasındaki farklara derinlemesine bir bakış için, TensorFlow 2.0'da Sembolik ve Zorunlu API'ler nedir? .
İşlevsel API güçleri:
Aşağıdaki özellikler Sıralı modeller için de geçerlidir (bunlar aynı zamanda veri yapılarıdır), ancak alt sınıflı modeller (veri yapıları değil Python bayt kodu olan) için doğru değildir.
Daha az ayrıntılı
super(MyClass, self).__init__(...)
, def call(self, ...):
vb. Yoktur.
Karşılaştırmak:
inputs = keras.Input(shape=(32,))
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
mlp = keras.Model(inputs, outputs)
Alt sınıflı sürümle:
class MLP(keras.Model):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
self.dense_1 = layers.Dense(64, activation='relu')
self.dense_2 = layers.Dense(10)
def call(self, inputs):
x = self.dense_1(inputs)
return self.dense_2(x)
# Instantiate the model.
mlp = MLP()
# Necessary to create the model's state.
# The model doesn't have a state until it's called at least once.
_ = mlp(tf.zeros((1, 32)))
Bağlantı grafiğini tanımlarken model doğrulama
İşlevsel API'de, giriş özelliği (şekil ve tip) önceden oluşturulur ( Input
kullanılarak). Bir katmanı her çağırdığınızda, katman, kendisine iletilen spesifikasyonun varsayımlarıyla eşleşip eşleşmediğini kontrol eder ve değilse faydalı bir hata mesajı verir.
Bu, işlevsel API ile oluşturabileceğiniz herhangi bir modelin çalışacağını garanti eder. Yakınsamayla ilgili hata ayıklama dışındaki tüm hata ayıklama işlemleri, yürütme sırasında değil, model oluşturma sırasında statik olarak gerçekleşir. Bu, bir derleyicide tür denetlemeye benzer.
İşlevsel bir model çizilebilir ve incelenebilir
Modeli grafik olarak çizebilir, bu grafikte ara düğümlere kolayca ulaşabilirsiniz. Örneğin, ara katmanların etkinleştirmelerini ayıklamak ve yeniden kullanmak için (önceki bir örnekte görüldüğü gibi):
features_list = [layer.output for layer in vgg19.layers]
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)
İşlevsel bir model serileştirilebilir veya klonlanabilir
İşlevsel bir model, bir kod parçası olmaktan ziyade bir veri yapısı olduğundan, güvenli bir şekilde serileştirilebilir ve orijinal koda erişmeden tam olarak aynı modeli yeniden oluşturmanıza olanak tanıyan tek bir dosya olarak kaydedilebilir. Serileştirme ve kaydetme kılavuzuna bakın .
Alt get_config()
bir modeli serileştirmek için, uygulayıcının model düzeyinde bir get_config()
ve from_config()
yöntemi belirtmesi get_config()
.
İşlevsel API zayıflığı:
Dinamik mimarileri desteklemez
İşlevsel API, modelleri katmanların DAG'leri olarak ele alır. Bu, çoğu derin öğrenme mimarisi için geçerlidir, ancak hepsi için geçerli değildir - örneğin, özyinelemeli ağlar veya Ağaç RNN'leri bu varsayımı takip etmez ve işlevsel API'de uygulanamaz.
API stillerini karıştır ve eşleştir
İşlevsel API veya Model alt sınıflandırma arasında seçim yapmak, sizi tek bir model kategorisiyle sınırlayan ikili bir karar değildir. tf.keras
API'sindeki tüm modeller, ister Sequential
modeller, ister işlevsel modeller veya sıfırdan yazılan alt tf.keras
modeller olsun, birbirleriyle etkileşim kurabilir.
Alt sınıflı bir modelin veya katmanın parçası olarak her zaman işlevsel bir model veya Sequential
model kullanabilirsiniz:
units = 32
timesteps = 10
input_dim = 5
# Define a Functional model
inputs = keras.Input((None, units))
x = layers.GlobalAveragePooling1D()(inputs)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)
class CustomRNN(layers.Layer):
def __init__(self):
super(CustomRNN, self).__init__()
self.units = units
self.projection_1 = layers.Dense(units=units, activation="tanh")
self.projection_2 = layers.Dense(units=units, activation="tanh")
# Our previously-defined Functional model
self.classifier = model
def call(self, inputs):
outputs = []
state = tf.zeros(shape=(inputs.shape[0], self.units))
for t in range(inputs.shape[1]):
x = inputs[:, t, :]
h = self.projection_1(x)
y = h + self.projection_2(state)
state = y
outputs.append(y)
features = tf.stack(outputs, axis=1)
print(features.shape)
return self.classifier(features)
rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, timesteps, input_dim)))
(1, 10, 32)
Aşağıdaki modellerden birini izleyen bir call
yöntemini uyguladığı sürece, işlevsel API'deki herhangi bir alt sınıf katmanı veya modeli kullanabilirsiniz:
-
call(self, inputs, **kwargs)
-inputs
bir tensör veya tensörlerin iç içe bir yapısı olduğu (örneğin, tensörlerin bir listesi) ve**kwargs
tensör olmayan argümanlar olduğu (giriş olmayanlar). -
call(self, inputs, training=None, **kwargs)
-training
, katmanın eğitim modunda ve çıkarım modunda davranması gerekip gerekmediğini belirten bir mantıksalcall(self, inputs, training=None, **kwargs)
. -
call(self, inputs, mask=None, **kwargs)
-mask
bir boole maskesi tensörü olduğu yerde (örneğin, RNN'ler için kullanışlıdır). -
call(self, inputs, training=None, mask=None, **kwargs)
- Elbette, aynı anda hem maskeleme hem de eğitime özgü davranışa sahip olabilirsiniz.
Ayrıca, özel Katman veya modelinize get_config
yöntemini get_config
, oluşturduğunuz işlevsel modeller yine de serileştirilebilir ve klonlanabilir olacaktır.
İşte sıfırdan yazılmış, işlevsel bir modelde kullanılan özel bir RNN'nin hızlı bir örneği:
units = 32
timesteps = 10
input_dim = 5
batch_size = 16
class CustomRNN(layers.Layer):
def __init__(self):
super(CustomRNN, self).__init__()
self.units = units
self.projection_1 = layers.Dense(units=units, activation="tanh")
self.projection_2 = layers.Dense(units=units, activation="tanh")
self.classifier = layers.Dense(1)
def call(self, inputs):
outputs = []
state = tf.zeros(shape=(inputs.shape[0], self.units))
for t in range(inputs.shape[1]):
x = inputs[:, t, :]
h = self.projection_1(x)
y = h + self.projection_2(state)
state = y
outputs.append(y)
features = tf.stack(outputs, axis=1)
return self.classifier(features)
# Note that you specify a static batch size for the inputs with the `batch_shape`
# arg, because the inner computation of `CustomRNN` requires a static batch size
# (when you create the `state` zeros tensor).
inputs = keras.Input(batch_shape=(batch_size, timesteps, input_dim))
x = layers.Conv1D(32, 3)(inputs)
outputs = CustomRNN()(x)
model = keras.Model(inputs, outputs)
rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, 10, 5)))