İşlevsel API

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

Kurmak

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

Tanıtım

Keras fonksiyonel API daha esnektir modelini oluşturmak için bir yöntemdir tf.keras.Sequential API. İşlevsel API, doğrusal olmayan topolojiye, paylaşılan katmanlara ve hatta birden çok girdi veya çıktıya sahip modelleri işleyebilir.

Ana fikir, bir derin öğrenme modelinin genellikle katmanların yönlendirilmiş bir döngüsel grafiği (DAG) olmasıdır. Fonksiyonel API Yani tabakaların grafikleri inşa etmek için bir yoldur.

Aşağıdaki modeli göz önünde bulundurun:

(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. İşlevsel API'yi kullanarak bu modeli oluşturmak için bir giriş düğümü oluşturarak başlayın:

inputs = keras.Input(shape=(784,))

Verinin şekli 784 boyutlu bir vektör olarak ayarlanır. Parti boyutu her zaman atlanır çünkü her örneğin sadece şekli belirtilir.

Örneğin, Eğer bir şekle sahip olan bir görüntü girişi varsa (32, 32, 3) , kullanmak olacaktır:

# Just for demonstration purposes.
img_inputs = keras.Input(shape=(32, 32, 3))

inputs döndürülen şekil ve hakkında bilgi içerir dtype size modeline besleyenler girdi verilerinin. İşte şekil:

inputs.shape
TensorShape([None, 784])

İşte tip:

inputs.dtype
tf.float32

Buna bir tabaka arayarak tabakaların grafikte yeni bir düğümün yaratılması inputs nesne:

dense = layers.Dense(64, activation="relu")
x = dense(inputs)

"Katman çağırma" eylemi, oluşturduğunuz bu katmana "girdilerden" bir ok çizmeye benzer. Sen sizsiniz, girdileri "geçen" dense tabakası ve aldığınız x çıktı olarak.

Katman grafiğine birkaç katman daha ekleyelim:

x = layers.Dense(64, activation="relu")(x)
outputs = layers.Dense(10)(x)

Bu noktada, bir oluşturabilir Model tabakalarının grafikte kendi giriş ve çıkışları ile belirli:

model = keras.Model(inputs=inputs, outputs=outputs, name="mnist_model")

Model özetinin nasıl göründüğüne 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 bir grafik olarak da çizebilirsiniz:

keras.utils.plot_model(model, "my_first_model.png")

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)

png

Bu şekil ve kod hemen hemen aynıdır. Kod versiyonunda, bağlantı okları çağrı işlemi ile değiştirilir.

"Katman grafiği", 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

Tam gelince fonksiyonel API kullanarak inşa modeller için aynı şekilde eğitim, değerlendirme ve çıkarım çalışmaları Sequential modelleri.

Model sınıf teklifler yerleşik bir eğitim döngüsü ( fit() yöntemi) ve yerleşik bir değerlendirme döngü ( evaluate() yöntemi). Kolayca ki Not bu döngüler özelleştirmek denetimli öğrenme ötesinde (örneğin eğitim rutinleri uygulamak Gans ).

Burada, MNIST görüntü verilerini yükleyin, vektörlere yeniden şekillendirin, modeli verilere sığdırın (bir doğrulama bölünmesinde 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.3430 - accuracy: 0.9035 - val_loss: 0.1851 - val_accuracy: 0.9463
Epoch 2/2
750/750 [==============================] - 2s 3ms/step - loss: 0.1585 - accuracy: 0.9527 - val_loss: 0.1366 - val_accuracy: 0.9597
313/313 - 0s - loss: 0.1341 - accuracy: 0.9592
Test loss: 0.13414572179317474
Test accuracy: 0.9592000246047974

Daha fazla okumak için bkz eğitim ve değerlendirme kılavuzu.

Kaydet ve seri hale getir

Modeli ve seri hale esere onlar için ne kadar işlevsel API kullanarak inşa modeller için aynı şekilde kaydetme Sequential modelleri. Fonksiyonel bir modelini kurtarmak için standart bir yol çağırmaktır model.save() tek bir dosya olarak tüm modeli kaydedin. Modeli oluşturan kod artık mevcut olmasa bile, daha sonra aynı modeli bu dosyadan yeniden oluşturabilirsiniz.

Bu kaydedilen dosya şunları içerir:

  • model mimarisi
  • model ağırlık değerleri (eğitim sırasında öğrenilen)
  • model eğitim yapılandırma, varsa (geçirilen olarak compile )
  • optimize edici 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")
2021-08-25 17:50:55.989736: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: path_to_my_model/assets

Ayrıntılar için, modeli okumak seri & tasarrufu kılavuzu.

Birden çok model tanımlamak için aynı katman grafiğini kullanın

İşlevsel API'de modeller, girdileri ve çıktıları bir katman grafiğinde belirtilerek oluşturulur. Bu, birden fazla model oluşturmak için tek bir katman grafiğinin kullanılabileceği anlamına gelir.

Aşağıdaki örnekte, iki model örneğini aynı katman yığını kullanın: Bir encoder bir model olduğu 16-boyutlu bir vektörleri içine döner görüntü girişi ve bir uç-uca autoencoder eğitim 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
_________________________________________________________________

Çıktı şekli girdi şekli ile aynıdır, bu nedenle burada dekode mimari, kodlama mimarisi tamamen simetrik olan (28, 28, 1) .

Bir ters Conv2D tabakası a, Conv2DTranspose tabakası ve bir arka MaxPooling2D tabakası bir olduğunu UpSampling2D katmanı.

Tüm modeller, katmanlar gibi çağrılabilir

Bir onu çağırarak bir katman sanki herhangi modeli tedavi edebilir Input ya da başka bir katmanın çıkışı üzerine. Bir modeli çağırarak, sadece modelin mimarisini yeniden kullanmıyorsunuz, aynı zamanda ağırlıklarını da yeniden kullanıyorsunuz.

Bunu çalışırken 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ğine farklı bir bakış:

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 iç içe olabilir: bir model alt modeller içerebilir (çünkü bir model bir katman gibidir). Model yuvalama için yaygın bir kullanım durumu asamblesi edilir. Ö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 yönetin

Çoklu giriş ve çıkışlı modeller

İşlevsel API, birden çok giriş ve çıkışı değiştirmeyi kolaylaştırır. Bu ele alınamaz Sequential API.

Örneğin, müşteri sorun biletlerini önceliğe göre sıralamak ve bunları doğru departmana yönlendirmek için bir sistem oluşturuyorsanız, modelin üç girişi 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 giriş)

Bu modelin iki çıktısı olacaktır:

  • 0 ile 1 arasındaki öncelik puanı (skaler sigmoid çıktısı) ve
  • bileti işlemesi gereken departman (departmanlar kümesi üzerinden softmax çıktısı).

İşlevsel API ile bu modeli 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)

png

Bu modeli derlerken her bir çıktıya farklı kayıplar atayabilirsiniz. Toplam eğitim kaybına katkılarını modüle etmek 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 adları farklı olduğundan, ilgili katman adlarıyla kayıp ve kayıp ağırlıkları da 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={"priority": 1.0, "department": 0.2},
)

NumPy girdi 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 [==============================] - 5s 9ms/step - loss: 1.2899 - priority_loss: 0.7186 - department_loss: 2.8564
Epoch 2/2
40/40 [==============================] - 0s 9ms/step - loss: 1.2668 - priority_loss: 0.6991 - department_loss: 2.8389
<keras.callbacks.History at 0x7fc1a66dc790>

Bir ile uyum ararken Dataset nesnesi, bu gibi listeleri bir demet ya vermelidir ([title_data, body_data, tags_data], [priority_targets, dept_targets]) ya da bu gibi sözlük bir başlığın ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets}) .

Daha ayrıntılı açıklama için bkz eğitim ve değerlendirme rehberi.

Bir oyuncak ResNet modeli

Birden fazla giriş ve çıkışları olan modellerde ek olarak, işlevsel bir API kolay doğrusal olmayan bağlantı topolojisini değiştirmek mümkün kılar - bu sırayla bağlı olmayan katmanlar, birlikte modelleri Sequential API işleyemez.

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)

png

Ş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 [==============================] - 11s 0us/step
170508288/170498071 [==============================] - 11s 0us/step
13/13 [==============================] - 2s 29ms/step - loss: 2.3364 - acc: 0.1063 - val_loss: 2.2986 - val_acc: 0.0850
<keras.callbacks.History at 0x7fc19df22610>

Paylaşılan katmanlar

Fonksiyonel API diğer bir avantajı paylaşılan katmanları kullanmak 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ığına sahip iki farklı metin parçası). Bu farklı girdiler arasında bilgi paylaşımını mümkün kılarlar ve böyle bir modelin daha az veri üzerinde eğitilmesini mümkün kılarlar. Girdilerden birinde belirli bir kelime görülürse, bu, paylaşılan katmandan geçen tüm girdilerin 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, burada bir var Embedding iki farklı metin girişleri arasında paylaşılır katman:

# 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

Manipüle ettiğiniz katmanların grafiği statik bir veri yapısı olduğu için erişilebilir ve incelenebilir. Ve bu şekilde işlevsel modelleri görüntü olarak çizebilirsiniz.

Bu ayrıca, ara katmanların (grafikteki "düğümler") aktivasyonlarına erişebileceğiniz ve bunları başka bir yerde yeniden kullanabileceğiniz anlamına gelir; bu, özellik çıkarma gibi bir şey için çok faydalı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 [==============================] - 15s 0us/step
574726144/574710816 [==============================] - 15s 0us/step

Ve bunlar, grafik veri yapısını sorgulayarak elde edilen modelin ara aktivasyonlarıdır:

features_list = [layer.output for layer in vgg19.layers]

Ara katman aktivasyonlarının değerlerini döndüren yeni bir özellik çıkarma modeli oluşturmak için bu ö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 gibi görevler için kullanışlı nöral tarzı transferi başka şeylerin yanı sıra,.

Özel katmanları kullanarak API'yi genişletin

tf.keras geniş bir yelpazede Dahili katmanlar, örneğin:

  • Evrişimsel katmanları: Conv1D , Conv2D , Conv3D , Conv2DTranspose
  • Havuzlaması katmanları: MaxPooling1D , MaxPooling2D , MaxPooling3D , AveragePooling1D
  • RYSA 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 alt sınıf Layer sınıfını ve uygulamak:

  • call yöntemi, yani belirtir katmanı tarafından yapılan hesaplama.
  • build tabakasının ağırlıklarını oluşturan yöntem, (eğer ağırlıkları oluşturabilir beri bu sadece bir stil kuralıdır __init__ sıra).

Sıfırdan katmanları oluşturma hakkında daha fazla bilgi edinmek okumak için özel katmanlar ve modelleri kılavuzu.

Aşağıdaki temel bir uygulamasıdır 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 tabakasında seri destek, bir tanımlayan get_config bir katman, örneğin kurucu bağımsız döner yöntem:

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, sınıf yöntemi uygulamak from_config(cls, config) bir tabaka örneği, yapılandırma sözlüğü verilmiştir yeniden zaman kullanılır. Varsayılan uygulama from_config geçerli:

def from_config(cls, config):
  return cls(**config)

İşlevsel API ne zaman kullanılır?

Yeni bir model oluşturmak, ya da sadece alt sınıf Keras fonksiyonel API kullanmalıyım Model doğrudan sınıfını? Genel olarak, işlevsel API daha yüksek düzeyde, daha kolay ve daha güvenlidir ve alt sınıf modellerin desteklemediği bir dizi özelliğe sahiptir.

Bununla birlikte, model alt sınıflama, yönlendirilmiş döngüsel olmayan katman grafikleri olarak kolayca ifade edilemeyen modeller oluştururken daha fazla esneklik sağlar. Örneğin, fonksiyonel API ile bir Ağaç RNN uygulamak olamazdı ve alt sınıf zorunda kalacak Model doğrudan.

Fonksiyonel API ve model subclassing arasındaki farklara derinlemesine bir görünüm için, okumak TensorFlow 2.0 Sembolik ve Emir API'ler nelerdir? .

İşlevsel API güçlü yönleri:

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 için doğru değildir (bunlar veri yapıları değil Python bayt kodudur).

Daha az ayrıntılı

Diye bir şey yok super(MyClass, self).__init__(...) hiç def call(self, ...): vs.

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ıf versiyonu ile:

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

Fonksiyonel API, giriş özellikleri (şekil ve d_type) (kullanarak önceden oluşturulur Input ). 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 yardımcı bir hata mesajı verir.

Bu, işlevsel API ile oluşturabileceğiniz herhangi bir modelin çalışacağını garanti eder. Yakınsama ile ilgili hata ayıklama dışındaki tüm hata ayıklama, yürütme zamanında değil, model oluşturma sırasında statik olarak gerçekleşir. Bu, bir derleyicide tip denetimine benzer.

İşlevsel bir model çizilebilir ve denetlenebilir

Modeli grafik olarak çizebilir ve bu grafikteki ara düğümlere kolayca ulaşabilirsiniz. Örneğin, ara katmanların aktivasyonlarını çıkarmak 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 seri hale getirilebilir veya klonlanabilir

İşlevsel bir model, bir kod parçasından ziyade bir veri yapısı olduğundan, güvenli bir şekilde seri hale getirilebilir ve orijinal kodlardan herhangi birine erişmeden aynı modeli yeniden oluşturmanıza olanak tanıyan tek bir dosya olarak kaydedilebilir. Bkz seri & tasarrufu kılavuzu .

Bir sınıflandırma modeli seri için, uygulayıcı bir belirlemek için gerekli olan get_config() ve from_config() modeli seviyesindeki bir yöntem.

İşlevsel API zayıflığı:

Dinamik mimarileri desteklemiyor

İşlevsel API, modelleri katmanların DAG'leri olarak ele alır. Bu, çoğu derin öğrenme mimarisi için geçerlidir, ancak tümü değil - örneğin, özyinelemeli ağlar veya Ağaç RNN'leri bu varsayımı izlemez ve işlevsel API'de uygulanamaz.

API stillerini karıştır ve eşleştir

İşlevsel API veya Model alt sınıflandırması arasında seçim yapmak, sizi tek bir model kategorisiyle sınırlayan ikili bir karar değildir. Tüm modeller tf.keras API onlar ister, birbirleriyle etkileşime girebilir Sequential modelleri, fonksiyonel modeller veya sıfırdan yazılır sınıflandırma modelleri.

Her zaman işlevsel bir model veya kullanabilir Sequential subclassed model veya katmanın bir parçası olarak modelini:

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)

Uzun bir uygulayan kadar işlevsel API herhangi sınıflandırma katmanı veya modeli kullanabilirsiniz call aşağıdaki desenlerden birini takip yöntemi:

  • call(self, inputs, **kwargs) - inputs bir tensör veya tensörlerinin iç içe bir yapı (tensörlerinin örneğin listesi) ve **kwargs olmayan tensör argümanlar (non-girişler) bulunmaktadır.
  • call(self, inputs, training=None, **kwargs) - training tabakası eğitim modu ve çıkarsama modunda davranması gerekip gerekmediğini gösteren bir boolean.
  • call(self, inputs, mask=None, **kwargs) - mask bir boolean maske tensörünü olduğu (örneğin, RNNs için faydalıdır).
  • call(self, inputs, training=None, mask=None, **kwargs) - Tabii ki, aynı anda hem maskeleme ve eğitim özgü davranış olabilir.

Eğer uygulamak Ek olarak, get_config özel Katmanı veya modele yöntemi, oluşturmak fonksiyonel modeller hala seri hale getirilebilir ve kopyalanabilen olacaktır.

İşlevsel bir modelde kullanılan, sıfırdan yazılmış ö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)))