The Functional API

با مجموعه‌ها، منظم بمانید ذخیره و دسته‌بندی محتوا براساس اولویت‌های شما.

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

برپایی

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

معرفی

از API های کاربردی Keras یک راه برای ایجاد مدل های که منعطف تر از است tf.keras.Sequential API. API عملکردی می تواند مدل هایی با توپولوژی غیر خطی، لایه های مشترک و حتی ورودی یا خروجی های متعدد را مدیریت کند.

ایده اصلی این است که یک مدل یادگیری عمیق معمولاً یک نمودار غیر چرخه ای جهت دار (DAG) از لایه ها است. بنابراین API کاربردی راه را برای ساخت نمودار های لایه است.

مدل زیر را در نظر بگیرید:

(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)

این یک نمودار پایه با سه لایه است. برای ساخت این مدل با استفاده از API کاربردی، با ایجاد یک گره ورودی شروع کنید:

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

شکل داده ها به صورت یک بردار 784 بعدی تنظیم شده است. اندازه دسته همیشه حذف می شود زیرا فقط شکل هر نمونه مشخص شده است.

اگر، برای مثال، شما باید یک ورودی تصویر با یک شکل (32, 32, 3) ، شما می توانید استفاده کنید:

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

inputs است که بازگشته حاوی اطلاعاتی در مورد شکل و dtype از داده های ورودی است که شما به مدل خود را تغذیه می کنند. این شکل است:

inputs.shape
TensorShape([None, 784])

اینم dtype:

inputs.dtype
tf.float32

شما ایجاد یک گره جدید در نمودار لایه با تماس با یک لایه در این inputs شی:

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

عمل "لایه فراخوانی" مانند کشیدن یک فلش از "ورودی ها" به این لایه است که ایجاد کرده اید. شما "عبور" ورودی به dense لایه، و شما می توانید x به عنوان خروجی.

بیایید چند لایه دیگر به نمودار لایه ها اضافه کنیم:

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

در این مرحله، شما می توانید یک ایجاد Model با مشخص ورودی و خروجیهای آن در نمودار لایه:

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

بیایید بررسی کنیم که خلاصه مدل چگونه به نظر می رسد:

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
_________________________________________________________________

همچنین می توانید مدل را به صورت نمودار رسم کنید:

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

png

و به صورت اختیاری، اشکال ورودی و خروجی هر لایه را در نمودار رسم شده نمایش دهید:

keras.utils.plot_model(model, "my_first_model_with_shape_info.png", show_shapes=True)

png

این رقم و کد تقریباً یکسان هستند. در نسخه کد، فلش های اتصال با عملیات تماس جایگزین می شوند.

«گراف لایه‌ها» یک تصویر ذهنی بصری برای یک مدل یادگیری عمیق است و API کاربردی راهی برای ایجاد مدل‌هایی است که دقیقاً این موضوع را منعکس می‌کند.

آموزش، ارزیابی و استنتاج

آموزش، ارزیابی، و کار استنتاج دقیقا در همان راه برای مدل های ساخته شده با استفاده از API های کاربردی به عنوان برای Sequential مدل.

Model کلاس ارائه می دهد ساخته شده است در حلقه آموزش (به fit() روش) و ساخته شده است در حلقه ارزیابی (به evaluate() روش). توجه داشته باشید که شما به راحتی می توانید این حلقه ها سفارشی برای پیاده سازی برنامه های تمرین فراتر از یادگیری تحت نظارت (به عنوان مثال گانز ).

در اینجا، داده‌های تصویر MNIST را بارگیری کنید، آن را به شکل بردارها تغییر دهید، مدل را روی داده‌ها قرار دهید (در حالی که عملکرد را در یک تقسیم اعتبارسنجی نظارت می‌کنید)، سپس مدل را روی داده‌های آزمایشی ارزیابی کنید:

(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

برای مطالعه بیشتر، نگاه کنید به آموزش و ارزیابی راهنمای.

ذخیره و سریال

صرفه جویی در مدل و ترتیب کار راه را برای همان مدل ساخته شده با استفاده از API های کاربردی به عنوان آنها را برای انجام Sequential مدل. روش استاندارد برای نجات یک مدل کاربردی است به تماس model.save() به صرفه جویی در کل مدل به عنوان یک فایل واحد. بعداً می‌توانید همان مدل را از این فایل دوباره ایجاد کنید، حتی اگر کدی که مدل را ساخته است دیگر در دسترس نباشد.

این فایل ذخیره شده شامل موارد زیر است:

  • معماری مدل
  • مقادیر وزن مدل (که در طول تمرین آموخته شد)
  • آموزش مدل پیکربندی، در صورت وجود (به عنوان گذشت compile )
  • بهینه ساز و وضعیت آن، در صورت وجود (برای شروع مجدد آموزش از جایی که متوقف کردید)
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

برای جزئیات بیشتر، به عنوان خوانده شده مدل ترتیب و صرفه جویی در راهنمای.

از همان نمودار لایه ها برای تعریف چندین مدل استفاده کنید

در API عملکردی، مدل‌ها با مشخص کردن ورودی‌ها و خروجی‌هایشان در نموداری از لایه‌ها ایجاد می‌شوند. این بدان معناست که می توان از یک نمودار واحد از لایه ها برای تولید چندین مدل استفاده کرد.

در مثال زیر، شما با استفاده از همان پشته لایه ها برای نمونه دو مدل: یک encoder مدل است که ورودی نوبت تصویر را به بردار 16 بعدی، و پایان به پایان autoencoder مدل برای آموزش است.

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
_________________________________________________________________

در اینجا، معماری رمزگشایی به شدت به معماری را پشتیبانی می کند متقارن است، پس شکل خروجی همان شکل ورودی است (28, 28, 1) .

معکوس یک Conv2D لایه است Conv2DTranspose لایه، و معکوس از یک MaxPooling2D لایه یک IS UpSampling2D لایه.

همه مدل ها مانند لایه ها قابل فراخوانی هستند

شما می توانید هر مدل را به عنوان اگر آن را یک لایه با استناد به آن را در یک بودند Input و یا بر روی خروجی یکی دیگر از لایه. با فراخوانی یک مدل، نه تنها از معماری مدل استفاده مجدد می‌کنید، بلکه از وزن‌های آن نیز استفاده می‌کنید.

برای مشاهده عملی این موضوع، در اینجا یک برداشت متفاوت از مثال رمزگذار خودکار است که یک مدل رمزگذار، یک مدل رمزگشا ایجاد می‌کند و آنها را در دو فراخوانی زنجیره‌ای می‌کند تا مدل رمزگذار خودکار را به دست آورد:

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
_________________________________________________________________

همانطور که می بینید، مدل می تواند تودرتو باشد: یک مدل می تواند شامل مدل های فرعی باشد (زیرا یک مدل درست مانند یک لایه است). مورد استفاده مشترک برای مدل تودرتو ensembling است. به عنوان مثال، در اینجا نحوه ترکیب مجموعه ای از مدل ها در یک مدل واحد که میانگین پیش بینی های آنها را محاسبه می کند، آمده است:

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)

توپولوژی های گراف پیچیده را دستکاری کنید

مدل هایی با ورودی و خروجی های متعدد

API کاربردی، دستکاری چندین ورودی و خروجی را آسان می کند. این می تواند با استفاده نیست Sequential API.

برای مثال، اگر سیستمی برای رتبه‌بندی بلیط‌های مربوط به مشتریان بر اساس اولویت و مسیریابی آن‌ها به بخش صحیح ایجاد می‌کنید، مدل سه ورودی خواهد داشت:

  • عنوان بلیط (ورودی متن)،
  • متن متن بلیط (ورودی متن)، و
  • هر تگ اضافه شده توسط کاربر (ورودی طبقه بندی)

این مدل دو خروجی خواهد داشت:

  • امتیاز اولویت بین 0 و 1 (خروجی سیگموئید اسکالر) و
  • بخشی که باید تیکت را مدیریت کند (خروجی softmax در مجموعه ای از بخش ها).

شما می توانید این مدل را در چند خط با API کاربردی بسازید:

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],
)

حالا مدل را رسم کنید:

keras.utils.plot_model(model, "multi_input_and_output_model.png", show_shapes=True)

png

هنگام کامپایل این مدل می توانید تلفات مختلفی را به هر خروجی اختصاص دهید. حتی می‌توانید وزن‌های مختلفی را به هر باخت اختصاص دهید - تا سهم آن‌ها در کاهش کل تمرین تعدیل شود.

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],
)

از آنجایی که لایه‌های خروجی نام‌های متفاوتی دارند، می‌توانید با نام لایه‌های مربوطه، وزن‌های تلفات و کاهش را نیز مشخص کنید:

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 از ورودی ها و اهداف، مدل را آموزش دهید:

# 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>

هنگامی که تماس مناسب با Dataset شیء، آن را باید یا یک تاپل از لیست ها مانند عملکرد ([title_data, body_data, tags_data], [priority_targets, dept_targets]) و یا یک تاپل از فرهنگ مانند ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets}) .

برای توضیح بیشتر، به مراجعه آموزش و ارزیابی راهنمای.

یک مدل ResNet اسباب بازی

علاوه بر مدل با ورودی و خروجی های متعدد، از API های کاربردی می سازد آن را آسان به دستکاری توپولوژی اتصال غیر خطی - این مدل با لایه های که به هم متصل نمی پی در پی، که می Sequential API نمی تواند اداره کند.

یک مورد معمول استفاده برای این اتصالات باقی مانده است. بیایید یک مدل ResNet اسباب بازی برای CIFAR10 بسازیم تا این را نشان دهیم:

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
__________________________________________________________________________________________________

مدل را ترسیم کنید:

keras.utils.plot_model(model, "mini_resnet.png", show_shapes=True)

png

حالا مدل را آموزش دهید:

(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>

لایه های مشترک

یکی دیگر از استفاده خوب برای API های کاربردی مدل های که با استفاده از لایه های به اشتراک گذاشته شده است. لایه های اشتراکی نمونه های لایه ای هستند که چندین بار در یک مدل مورد استفاده مجدد قرار می گیرند -- آنها ویژگی هایی را یاد می گیرند که با چندین مسیر در گراف لایه ها مطابقت دارند.

لایه های مشترک اغلب برای رمزگذاری ورودی ها از فضاهای مشابه (مثلاً دو قطعه متن متفاوت که دارای واژگان مشابه هستند) استفاده می شود. آنها به اشتراک گذاری اطلاعات را در این ورودی های مختلف امکان پذیر می کنند و آموزش چنین مدلی را بر روی داده های کمتر ممکن می سازند. اگر کلمه معینی در یکی از ورودی‌ها دیده شود، پردازش تمام ورودی‌هایی که از لایه مشترک عبور می‌کنند مفید خواهد بود.

برای به اشتراک گذاشتن یک لایه در API عملکردی، یک نمونه لایه را چندین بار فراخوانی کنید. به عنوان مثال، در اینجا یک است Embedding لایه مشترک در سراسر دو ورودی متن های مختلف:

# 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)

استخراج و استفاده مجدد از گره ها در نمودار لایه ها

از آنجایی که نمودار لایه هایی که شما دستکاری می کنید یک ساختار داده ایستا است، می توان به آن دسترسی و بازرسی کرد. و به این ترتیب می توانید مدل های کاربردی را به عنوان تصویر ترسیم کنید.

این همچنین به این معنی است که می‌توانید به فعال‌سازی لایه‌های میانی («گره‌ها» در نمودار) دسترسی داشته باشید و از آن‌ها در جاهای دیگر استفاده کنید - که برای چیزی مانند استخراج ویژگی بسیار مفید است.

بیایید به یک مثال نگاه کنیم. این یک مدل VGG19 با وزنه های از قبل آموزش داده شده در ImageNet است:

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

و اینها فعال سازی های میانی مدل هستند که با پرس و جو در ساختار داده گراف به دست می آیند:

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

از این ویژگی‌ها برای ایجاد یک مدل استخراج ویژگی جدید استفاده کنید که مقادیر فعال‌سازی لایه میانی را برمی‌گرداند:

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)

این می آید در دستی برای انجام وظایف مانند انتقال سبک های عصبی ، در میان چیزهای دیگر.

API را با استفاده از لایه های سفارشی گسترش دهید

tf.keras شامل طیف گسترده ای از ساخته شده است در لایه ها، به عنوان مثال:

  • لایه های کانولوشن: Conv1D ، Conv2D ، Conv3D ، Conv2DTranspose
  • لایه های ادغام: MaxPooling1D ، MaxPooling2D ، MaxPooling3D ، AveragePooling1D
  • لایه RNN: GRU ، LSTM ، ConvLSTM2D
  • BatchNormalization ، Dropout ، Embedding ، و غیره

اما اگر آنچه را که نیاز دارید پیدا نکردید، گسترش API با ایجاد لایه‌های خود آسان است. تمام لایه های زیر مجموعه Layer کلاس و پیاده سازی:

  • call روش، که مشخص محاسبه انجام شده توسط لایه.
  • build روش، که باعث ایجاد وزن لایه (این فقط یک قرارداد سبک است شما می توانید وزن در ایجاد __init__ ، و همچنین به).

برای کسب اطلاعات بیشتر در مورد ایجاد لایه، از ابتدا، به عنوان خوانده شده لایه های سفارشی و مدل های راهنمای.

در زیر به اجرای اولیه است 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)

برای پشتیبانی ترتیب در لایه های سفارشی خود را، تعریف یک get_config روش که آرگومان های سازنده به عنوان مثال لایه را بر می گرداند:

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})

در صورت تمایل، پیاده سازی روش کلاس from_config(cls, config) استفاده شده است که در هنگام بازآفرینی یک نمونه لایه داده فرهنگ لغت پیکربندی آن است. پیاده سازی پیش فرض از from_config است:

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

زمان استفاده از API کاربردی

باید به شما استفاده از API های کاربردی Keras برای ایجاد یک مدل جدید، یا فقط زیر مجموعه Model کلاس به طور مستقیم. به طور کلی، API عملکردی سطح بالاتر، آسان‌تر و ایمن‌تر است و دارای تعدادی ویژگی است که مدل‌های زیر کلاس از آن‌ها پشتیبانی نمی‌کنند.

با این حال، طبقه‌بندی فرعی مدل، انعطاف‌پذیری بیشتری را هنگام ساخت مدل‌هایی که به‌راحتی به‌عنوان نمودارهای غیرچرخه‌ای لایه‌ها قابل بیان نیستند، فراهم می‌کند. به عنوان مثال، شما می توانید یک درخت RNN با API کاربردی پیاده سازی نیست و باید به زیر کلاس Model به طور مستقیم.

برای در تفاوت بین API کاربردی و مدل subclassing در عمق نگاه، به عنوان خوانده شده رابط های برنامه کاربردی نمادین و دستوری در TensorFlow 2.0 چیست؟ .

نقاط قوت API عملکردی:

ویژگی‌های زیر برای مدل‌های ترتیبی (که ساختارهای داده نیز هستند) صادق است، اما برای مدل‌های زیر کلاس (که بایت کد پایتون هستند، نه ساختار داده) صادق نیستند.

کمتر پرمخاطب

است وجود نداشت super(MyClass, self).__init__(...) ، هیچ def call(self, ...): ، و غیره

مقایسه کنید:

inputs = keras.Input(shape=(32,))
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
mlp = keras.Model(inputs, outputs)

با نسخه زیر کلاس:

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)))

اعتبارسنجی مدل در حین تعریف نمودار اتصال آن

در API کاربردی، مشخصات ورودی (شکل و dtype) در پیش ایجاد شده است (با استفاده از Input ). هر بار که یک لایه را فراخوانی می‌کنید، لایه بررسی می‌کند که مشخصات ارسال شده به آن با مفروضاتش مطابقت دارد و در غیر این صورت یک پیغام خطای مفید ایجاد می‌کند.

این تضمین می کند که هر مدلی که می توانید با API کاربردی بسازید اجرا خواهد شد. تمام اشکال زدایی - به غیر از اشکال زدایی مربوط به همگرایی - به صورت ایستا در طول ساخت مدل اتفاق می افتد و نه در زمان اجرا. این شبیه به بررسی تایپ در یک کامپایلر است.

یک مدل کاربردی قابل ترسیم و بازرسی است

شما می توانید مدل را به صورت نمودار رسم کنید و به راحتی می توانید به گره های میانی در این نمودار دسترسی داشته باشید. به عنوان مثال، برای استخراج و استفاده مجدد از فعال سازی لایه های میانی (همانطور که در مثال قبلی مشاهده شد):

features_list = [layer.output for layer in vgg19.layers]
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)

یک مدل عملکردی را می توان سریالی یا شبیه سازی کرد

از آنجایی که یک مدل عملکردی یک ساختار داده است و نه یک قطعه کد، به طور ایمن قابل سریال‌سازی است و می‌توان آن را به عنوان یک فایل ذخیره کرد که به شما امکان می‌دهد دقیقاً همان مدل را بدون دسترسی به کد اصلی بازسازی کنید. مراجعه کنید به ترتیب و صرفه جویی در راهنمای .

برای مرتب یک مدل subclassed، لازم است برای تطبیق برای مشخص کردن یک get_config() و from_config() روش در سطح مدل.

ضعف عملکردی API:

از معماری های پویا پشتیبانی نمی کند

API کاربردی مدل ها را به عنوان DAG لایه ها در نظر می گیرد. این برای اکثر معماری‌های یادگیری عمیق صادق است، اما نه همه - برای مثال، شبکه‌های بازگشتی یا RNNهای درختی از این فرض پیروی نمی‌کنند و نمی‌توانند در API عملکردی پیاده‌سازی شوند.

ترکیب و تطبیق سبک های API

انتخاب بین API کاربردی یا زیر کلاس مدل یک تصمیم باینری نیست که شما را به یک دسته از مدل ها محدود کند. همه مدل ها در tf.keras API می تواند در تعامل با یکدیگر، که آیا آنها Sequential مدل، مدل های تابعی، یا مدل subclassed که از ابتدا نوشته شده است.

شما همیشه می توانید یک مدل کاربردی و یا استفاده از Sequential مدل به عنوان بخشی از یک مدل subclassed یا لایه:

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)

شما می توانید هر لایه subclassed یا مدل در API کاربردی تا زمانی که آن را پیاده سازی استفاده از call روشی است که از یکی از الگوهای زیر است:

  • call(self, inputs, **kwargs) - از کجا inputs یک تانسور یا یک ساختار تو در تو از تانسورها (به عنوان مثال یک لیست از تانسورها) است، و که در آن **kwargs استدلال غیر تانسور (غیر ورودی) می باشد.
  • call(self, inputs, training=None, **kwargs) - از کجا training بولی نشان می دهد آیا لایه باید در حالت آموزش و حالت استنتاج رفتار است.
  • call(self, inputs, mask=None, **kwargs) - از کجا mask یک تانسور ماسک boolean است (مفید برای RNNs، به عنوان مثال).
  • call(self, inputs, training=None, mask=None, **kwargs) - البته، شما می توانید هر دو پوشش و رفتار آموزش های خاص در همان زمان داشته باشد.

علاوه بر این، اگر شما در اجرای get_config روش در لایه های سفارشی و یا مدل خود، مدل های کاربردی شما ایجاد خواهد کرد هنوز هم serializable و cloneable باشد.

در اینجا یک مثال سریع از یک RNN سفارشی است که از ابتدا نوشته شده و در یک مدل کاربردی استفاده می شود:

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)))