مدل های Keras را ذخیره و بارگذاری کنید

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

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

معرفی

یک مدل Keras از چندین جزء تشکیل شده است:

  • معماری یا پیکربندی که مشخص می کند مدل شامل چه لایه هایی است و چگونه به هم متصل می شوند.
  • مجموعه ای از مقادیر وزن ("وضعیت مدل").
  • یک بهینه ساز (تعریف شده با کامپایل مدل).
  • مجموعه ای از تلفات و معیارهای (تعریف شده توسط تدوین مدل یا تماس add_loss() و یا add_metric() ).

Keras API این امکان را فراهم می کند که همه این قطعات را به طور همزمان روی دیسک ذخیره کنید یا فقط برخی از آنها را به صورت انتخابی ذخیره کنید:

  • ذخیره همه چیز در یک بایگانی واحد در قالب TensorFlow SavedModel (یا در قالب قدیمی Keras H5). این روش استاندارد است.
  • صرفه جویی در معماری/پیکربندی، معمولاً به صورت فایل JSON.
  • صرفه جویی در مقادیر وزن. این معمولاً هنگام آموزش مدل استفاده می شود.

بیایید نگاهی به هر یک از این گزینه ها بیندازیم. چه زمانی از یکی یا دیگری استفاده می کنید و چگونه کار می کنند؟

نحوه ذخیره و بارگذاری یک مدل

اگر فقط 10 ثانیه برای خواندن این راهنما فرصت دارید، در اینجا چیزی است که باید بدانید.

ذخیره یک مدل Keras:

model = ...  # Get model (Sequential, Functional Model, or Model subclass)
model.save('path/to/location')

بارگیری مجدد مدل:

from tensorflow import keras
model = keras.models.load_model('path/to/location')

حالا بیایید به جزئیات نگاه کنیم.

برپایی

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

ذخیره و بارگیری کل مدل

شما می توانید کل مدل را در یک مصنوع ذخیره کنید. شامل موارد زیر خواهد بود:

  • معماری/پیکربندی مدل
  • مقادیر وزن مدل (که در طول تمرین آموخته شد)
  • اطلاعات تلفیقی مدل را (در صورت compile() نامیده می شد)
  • بهینه ساز و وضعیت آن، در صورت وجود (این به شما امکان می دهد آموزش را از جایی که ترک کرده اید مجدداً شروع کنید)

API ها

دو فرمت شما می توانید استفاده کنید برای ذخیره یک مدل کل بر روی دیسک وجود دارد: فرمت TensorFlow SavedModel، و بالاتر فرمت Keras H5. فرمت پیشنهادی SavedModel است. این پیش فرض است که هنگام استفاده از model.save() .

شما می توانید به فرمت H5 تغییر دهید:

  • عبور save_format='h5' به save() .
  • عبور از یک نام فایل که به پایان می رسد در .h5 یا .keras به save() .

فرمت SavedModel

SavedModel قالب ذخیره جامع تری است که معماری مدل، وزن ها و زیرگراف های Tensorflow ردیابی شده توابع فراخوانی را ذخیره می کند. این به Keras امکان می‌دهد هم لایه‌های داخلی و هم اشیاء سفارشی را بازیابی کند.

مثال:

def get_model():
    # Create a simple model.
    inputs = keras.Input(shape=(32,))
    outputs = keras.layers.Dense(1)(inputs)
    model = keras.Model(inputs, outputs)
    model.compile(optimizer="adam", loss="mean_squared_error")
    return model


model = get_model()

# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)

# Calling `save('my_model')` creates a SavedModel folder `my_model`.
model.save("my_model")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_model")

# Let's check:
np.testing.assert_allclose(
    model.predict(test_input), reconstructed_model.predict(test_input)
)

# The reconstructed model is already compiled and has retained the optimizer
# state, so training can resume:
reconstructed_model.fit(test_input, test_target)
4/4 [==============================] - 1s 2ms/step - loss: 0.5884
2021-08-25 17:49:05.320893: 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: my_model/assets
4/4 [==============================] - 0s 2ms/step - loss: 0.5197
<keras.callbacks.History at 0x7f99486ad490>

آنچه که SavedModel شامل می شود

تماس model.save('my_model') ایجاد یک پوشه به نام my_model ، حاوی موارد زیر است:

ls my_model
assets  keras_metadata.pb  saved_model.pb  variables

معماری مدل، و پیکربندی آموزش (از جمله بهینه ساز، تلفات، و معیارهای) ذخیره شده در saved_model.pb . وزن ها در ذخیره variables/ دایرکتوری.

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

چگونه SavedModel اشیاء سفارشی را مدیریت می کند

هنگام ذخیره کردن مدل و لایه های آن، SavedModel فرمت های نام کلاس، تابع پاسخ، تلفات، و وزن (و پیکربندی، در صورت اجرا). تابع فراخوانی نمودار محاسباتی مدل/لایه را تعریف می کند.

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

با این وجود، آن است که همیشه یک تمرین خوب برای تعریف get_config و from_config روش در هنگام نوشتن یک مدل سفارشی و یا کلاس لایه. این به شما این امکان را می دهد که در صورت نیاز به راحتی محاسبات را بعداً به روز کنید. بخش مورد مشاهده اشیاء سفارشی برای اطلاعات بیشتر.

مثال:

class CustomModel(keras.Model):
    def __init__(self, hidden_units):
        super(CustomModel, self).__init__()
        self.hidden_units = hidden_units
        self.dense_layers = [keras.layers.Dense(u) for u in hidden_units]

    def call(self, inputs):
        x = inputs
        for layer in self.dense_layers:
            x = layer(x)
        return x

    def get_config(self):
        return {"hidden_units": self.hidden_units}

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


model = CustomModel([16, 16, 10])
# Build the model by calling it
input_arr = tf.random.uniform((1, 5))
outputs = model(input_arr)
model.save("my_model")

# Option 1: Load with the custom_object argument.
loaded_1 = keras.models.load_model(
    "my_model", custom_objects={"CustomModel": CustomModel}
)

# Option 2: Load without the CustomModel class.

# Delete the custom-defined model class to ensure that the loader does not have
# access to it.
del CustomModel

loaded_2 = keras.models.load_model("my_model")
np.testing.assert_allclose(loaded_1(input_arr), outputs)
np.testing.assert_allclose(loaded_2(input_arr), outputs)

print("Original model:", model)
print("Model Loaded with custom objects:", loaded_1)
print("Model loaded without the custom object class:", loaded_2)
INFO:tensorflow:Assets written to: my_model/assets
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
Original model: <__main__.CustomModel object at 0x7f9949c86810>
Model Loaded with custom objects: <__main__.CustomModel object at 0x7f99681f61d0>
Model loaded without the custom object class: <keras.saving.saved_model.load.CustomModel object at 0x7f9aaceefd10>

اولین مدل لود شده است با استفاده از پیکربندی و لود CustomModel کلاس. مدل دوم با ایجاد پویا کلاس مدل که مانند مدل اصلی عمل می کند بارگذاری می شود.

پیکربندی SavedModel

جدید در 2.4 TensoFlow استدلال save_traces اضافه شده است برای model.save ، که شما اجازه می دهد تا به ضامن SavedModel عملکرد ردیابی است. توابع ذخیره شده اجازه می دهد تا Keras به اشیاء سفارشی دوباره بار بدون definitons کلاس اصلی، تا زمانی که save_traces=False ، تمام اشیاء سفارشی باید تعریف کرده اند get_config / from_config روش. هنگام بارگذاری، اشیاء سفارشی باید به تصویب custom_objects استدلال است. save_traces=False فضای دیسک استفاده شده توسط SavedModel و صرفه جویی در زمان را کاهش می دهد.

فرمت Keras H5

Keras همچنین پشتیبانی از صرفه جویی در یک فایل HDF5 واحد شامل معماری مدل، ارزش وزن، و compile() اطلاعات است. این یک جایگزین سبک وزن برای SavedModel است.

مثال:

model = get_model()

# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)

# Calling `save('my_model.h5')` creates a h5 file `my_model.h5`.
model.save("my_h5_model.h5")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_h5_model.h5")

# Let's check:
np.testing.assert_allclose(
    model.predict(test_input), reconstructed_model.predict(test_input)
)

# The reconstructed model is already compiled and has retained the optimizer
# state, so training can resume:
reconstructed_model.fit(test_input, test_target)
4/4 [==============================] - 0s 1ms/step - loss: 1.6322
4/4 [==============================] - 0s 1ms/step - loss: 1.4790
<keras.callbacks.History at 0x7f9aacc0fd50>

محدودیت ها

در مقایسه با فرمت SavedModel، دو مورد وجود دارد که در فایل H5 گنجانده نمی شود:

  • زیان خارجی و معیارهای افزوده شده از طریق model.add_loss() و model.add_metric() هستند (بر خلاف SavedModel) ذخیره نمی شود. اگر چنین تلفات و معیارهایی در مدل خود دارید و می‌خواهید آموزش را از سر بگیرید، باید پس از بارگذاری مدل، این ضررها را خودتان اضافه کنید. توجه داشته باشید که این به زیان / معیارهای داخل لایه ها از طریق ایجاد نمی شود self.add_loss() و self.add_metric() . تا زمانی که لایه لود می شود، این زیانها و معیارهای نگهداری می شوند، چرا که آنها بخشی از هستند call روش از لایه.
  • نمودار محاسبه سفارشی اشیاء مانند لایه های سفارشی در فایل های ذخیره شده گنجانده نشده است. در زمان بارگذاری، Keras برای بازسازی مدل نیاز به دسترسی به کلاس ها/توابع Python این اشیا دارد. مشاهده سفارشی اشیاء .

نجات معماری

پیکربندی (یا معماری) مدل مشخص می‌کند که مدل شامل چه لایه‌هایی است و چگونه این لایه‌ها به هم متصل می‌شوند*. اگر پیکربندی یک مدل را دارید، می توان مدل را با حالت اولیه اولیه برای وزن ها و بدون اطلاعات کامپایل ایجاد کرد.

*توجه داشته باشید که این فقط برای مدل‌هایی اعمال می‌شود که با استفاده از مدل‌های تابعی یا Sequential apis تعریف شده‌اند، نه زیر کلاس.

پیکربندی یک مدل متوالی یا مدل تابعی API

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

API ها

get_config() و from_config()

تماس config = model.get_config() یک دیکشنری پایتون حاوی تنظیمات از مدل بازگشت. همان مدل پس از آن می توانید از طریق بازسازی شود Sequential.from_config(config) (برای یک Sequential مدل) و یا Model.from_config(config) (برای یک مدل API کاربردی).

همین گردش کار برای هر لایه قابل سریال سازی نیز کار می کند.

مثال لایه:

layer = keras.layers.Dense(3, activation="relu")
layer_config = layer.get_config()
new_layer = keras.layers.Dense.from_config(layer_config)

مثال مدل متوالی:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
config = model.get_config()
new_model = keras.Sequential.from_config(config)

نمونه مدل عملکردی:

inputs = keras.Input((32,))
outputs = keras.layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)
config = model.get_config()
new_model = keras.Model.from_config(config)

to_json() و tf.keras.models.model_from_json()

این شبیه به است get_config / from_config ، به جز آن را تبدیل به مدل را به یک رشته JSON، که پس از آن می توانید بدون طبقه مدل اصلی بارگذاری می شود. همچنین مختص مدل ها است، برای لایه ها در نظر گرفته نشده است.

مثال:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
json_config = model.to_json()
new_model = keras.models.model_from_json(json_config)

اشیاء سفارشی

مدل ها و لایه ها

معماری مدل subclassed و لایه ها در روش های تعریف شده __init__ و call . آنها در نظر گرفته پایتون بایت کد، که می تواند به یک پیکربندی JSON سازگار نمی شود مرتب - شما می توانید سعی serialize کردن بایت کد (برای مثال از طریق pickle )، اما آن را کاملا ناامن و معنی مدل خود را می توانید بر روی سیستم های مختلف نمی تواند لود شود.

به منظور ذخیره / بار یک مدل با لایه های سفارشی تعریف، و یا یک مدل subclassed، شما باید بازنویسی get_config و به صورت اختیاری from_config روش. علاوه بر این، باید از ثبت شی سفارشی استفاده کنید تا Keras از آن آگاه باشد.

توابع سفارشی

توابع سفارشی تعریف شده (به عنوان مثال از دست دادن فعال سازی و یا مقدار دهی اولیه) یک نیاز get_config روش. نام تابع تا زمانی که به عنوان یک شی سفارشی ثبت شده باشد برای بارگیری کافی است.

فقط در حال بارگیری نمودار TensorFlow

بارگیری نمودار TensorFlow تولید شده توسط Keras امکان پذیر است. اگر شما انجام این کار، شما نیاز به ارائه هر گونه custom_objects . شما می توانید این کار را به این صورت انجام دهید:

model.save("my_model")
tensorflow_graph = tf.saved_model.load("my_model")
x = np.random.uniform(size=(4, 32)).astype(np.float32)
predicted = tensorflow_graph(x).numpy()
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
INFO:tensorflow:Assets written to: my_model/assets

توجه داشته باشید که این روش چندین اشکال دارد:

  • به دلایل قابلیت ردیابی، همیشه باید به اشیاء سفارشی استفاده شده دسترسی داشته باشید. شما نمی خواهید مدلی را تولید کنید که نتوانید آن را دوباره بسازید.
  • هدف بازگردانده شده توسط tf.saved_model.load یک مدل Keras است. بنابراین استفاده از آن به این راحتی نیست. به عنوان مثال، شما نمی خواهد به اینترنت دسترسی دارند .predict() و یا .fit()

حتی اگر استفاده از آن دلسرد شده است، می تواند شما اگر شما در یک نقطه تنگ هستید، برای مثال، اگر شما کد از اشیاء سفارشی خود را از دست داده و یا مسائل مربوط به بارگذاری مدل با اند tf.keras.models.load_model() .

شما می توانید در پیدا کردن اطلاعات بیشتر صفحه در مورد tf.saved_model.load

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

مشخصات فنی:

  • get_config باید یک دیکشنری JSON-serializable در بازگشت می شود سازگار با Keras معماری، و رابط های برنامه کاربردی مدل صرفه جویی در.
  • from_config(config) ( classmethod ) باید یک لایه و یا مدل شی جدید است که در config ایجاد گشت. پیاده سازی پیش فرض بازده cls(**config) .

مثال:

class CustomLayer(keras.layers.Layer):
    def __init__(self, a):
        self.var = tf.Variable(a, name="var_a")

    def call(self, inputs, training=False):
        if training:
            return inputs * self.var
        else:
            return inputs

    def get_config(self):
        return {"a": self.var.numpy()}

    # There's actually no need to define `from_config` here, since returning
    # `cls(**config)` is the default behavior.
    @classmethod
    def from_config(cls, config):
        return cls(**config)


layer = CustomLayer(5)
layer.var.assign(2)

serialized_layer = keras.layers.serialize(layer)
new_layer = keras.layers.deserialize(
    serialized_layer, custom_objects={"CustomLayer": CustomLayer}
)

ثبت شی سفارشی

Keras یادداشت می کند که کدام کلاس پیکربندی را ایجاد کرده است. از مثال بالا، tf.keras.layers.serialize تولید یک فرم سریال از لایه های سفارشی:

{'class_name': 'CustomLayer', 'config': {'a': 2} }

Keras نگه می دارد یک لیست استاد تمام ساخته شده است در لایه، مدل، بهینه ساز، و کلاس های متریک، استفاده شده است که برای پیدا کردن کلاس صحیح به پاسخ from_config . اگر طبقه را نمی توان یافت، سپس خطا مطرح شده است ( Value Error: Unknown layer ). چند راه برای ثبت کلاس های سفارشی در این لیست وجود دارد:

  1. تنظیم custom_objects استدلال در تابع در حال بارگذاری. (به مثال در بخش بالا "تعریف روش های پیکربندی" مراجعه کنید)
  2. tf.keras.utils.custom_object_scope یا tf.keras.utils.CustomObjectScope
  3. tf.keras.utils.register_keras_serializable

مثال لایه سفارشی و تابع

class CustomLayer(keras.layers.Layer):
    def __init__(self, units=32, **kwargs):
        super(CustomLayer, self).__init__(**kwargs)
        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):
        config = super(CustomLayer, self).get_config()
        config.update({"units": self.units})
        return config


def custom_activation(x):
    return tf.nn.tanh(x) ** 2


# Make a model with the CustomLayer and custom_activation
inputs = keras.Input((32,))
x = CustomLayer(32)(inputs)
outputs = keras.layers.Activation(custom_activation)(x)
model = keras.Model(inputs, outputs)

# Retrieve the config
config = model.get_config()

# At loading time, register the custom objects with a `custom_object_scope`:
custom_objects = {"CustomLayer": CustomLayer, "custom_activation": custom_activation}
with keras.utils.custom_object_scope(custom_objects):
    new_model = keras.Model.from_config(config)

شبیه سازی مدل در حافظه

شما همچنین می توانید در حافظه شبیه سازی یک مدل کار را از طریق tf.keras.models.clone_model() . این معادل دریافت پیکربندی و سپس ایجاد مجدد مدل از پیکربندی آن است (بنابراین اطلاعات کامپایل یا مقادیر وزن لایه ها حفظ نمی شود).

مثال:

with keras.utils.custom_object_scope(custom_objects):
    new_model = keras.models.clone_model(model)

فقط مقادیر وزن مدل را ذخیره و بارگذاری می کند

شما می توانید انتخاب کنید که فقط وزن های یک مدل را ذخیره و بارگذاری کنید. این می تواند مفید باشد اگر:

  • شما فقط به مدل برای استنتاج نیاز دارید: در این صورت نیازی به راه اندازی مجدد آموزش نخواهید داشت، بنابراین به اطلاعات کامپایل یا وضعیت بهینه ساز نیاز ندارید.
  • شما در حال یادگیری انتقالی هستید: در این مورد، یک مدل جدید را آموزش می‌دهید که از حالت یک مدل قبلی استفاده مجدد می‌کند، بنابراین به اطلاعات کامپایل مدل قبلی نیازی ندارید.

API برای انتقال وزن در حافظه

وزن را می توان بین اشیاء مختلف با استفاده از کپی get_weights و set_weights :

نمونه های زیر

انتقال وزن از یک لایه به لایه دیگر، در حافظه

def create_layer():
    layer = keras.layers.Dense(64, activation="relu", name="dense_2")
    layer.build((None, 784))
    return layer


layer_1 = create_layer()
layer_2 = create_layer()

# Copy weights from layer 1 to layer 2
layer_2.set_weights(layer_1.get_weights())

انتقال وزن از یک مدل به مدل دیگر با معماری سازگار، در حافظه

# Create a simple functional model
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

# Define a subclassed model with the same architecture
class SubclassedModel(keras.Model):
    def __init__(self, output_dim, name=None):
        super(SubclassedModel, self).__init__(name=name)
        self.output_dim = output_dim
        self.dense_1 = keras.layers.Dense(64, activation="relu", name="dense_1")
        self.dense_2 = keras.layers.Dense(64, activation="relu", name="dense_2")
        self.dense_3 = keras.layers.Dense(output_dim, name="predictions")

    def call(self, inputs):
        x = self.dense_1(inputs)
        x = self.dense_2(x)
        x = self.dense_3(x)
        return x

    def get_config(self):
        return {"output_dim": self.output_dim, "name": self.name}


subclassed_model = SubclassedModel(10)
# Call the subclassed model once to create the weights.
subclassed_model(tf.ones((1, 784)))

# Copy weights from functional_model to subclassed_model.
subclassed_model.set_weights(functional_model.get_weights())

assert len(functional_model.weights) == len(subclassed_model.weights)
for a, b in zip(functional_model.weights, subclassed_model.weights):
    np.testing.assert_allclose(a.numpy(), b.numpy())

مورد لایه های بدون تابعیت

از آنجایی که لایه‌های بدون حالت ترتیب یا تعداد وزن‌ها را تغییر نمی‌دهند، مدل‌ها می‌توانند معماری‌های سازگاری داشته باشند، حتی اگر لایه‌های بدون حالت اضافی/فقدان وجود داشته باشد.

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)

# Add a dropout layer, which does not contain any weights.
x = keras.layers.Dropout(0.5)(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model_with_dropout = keras.Model(
    inputs=inputs, outputs=outputs, name="3_layer_mlp"
)

functional_model_with_dropout.set_weights(functional_model.get_weights())

APIهایی برای ذخیره وزن در دیسک و بارگذاری مجدد آنها

وزن را می توان بر روی دیسک با تماس های ذخیره شده model.save_weights در فرمت های زیر:

  • ایست بازرسی تنسورفلو
  • HDF5

فرمت پیش فرض برای model.save_weights TensorFlow ایست بازرسی است. دو راه برای تعیین فرمت ذخیره وجود دارد:

  1. save_format استدلال: تنظیم مقدار به save_format="tf" یا save_format="h5" .
  2. path استدلال: اگر به پایان می رسد مسیر با .h5 یا .hdf5 ، سپس فرمت HDF5 استفاده شده است. دیگر پسوندها در یک ایستگاه بازرسی TensorFlow منجر خواهد شد مگر اینکه save_format تنظیم شده است.

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

فرمت TF Checkpoint

مثال:

# Runnable example
sequential_model = keras.Sequential(
    [
        keras.Input(shape=(784,), name="digits"),
        keras.layers.Dense(64, activation="relu", name="dense_1"),
        keras.layers.Dense(64, activation="relu", name="dense_2"),
        keras.layers.Dense(10, name="predictions"),
    ]
)
sequential_model.save_weights("ckpt")
load_status = sequential_model.load_weights("ckpt")

# `assert_consumed` can be used as validation that all variable values have been
# restored from the checkpoint. See `tf.train.Checkpoint.restore` for other
# methods in the Status object.
load_status.assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca4ced0>

جزئیات را قالب بندی کنید

فرمت TensorFlow Checkpoint وزن ها را با استفاده از نام ویژگی های شی ذخیره و بازیابی می کند. به عنوان مثال، در نظر گرفتن tf.keras.layers.Dense لایه. لایه شامل دو وزن: dense.kernel و dense.bias . هنگامی که لایه به ذخیره tf فرمت، ایست بازرسی در نتیجه شامل کلید های "kernel" و "bias" و مقادیر وزن متناظر با آنها. برای اطلاعات بیشتر به "مکانیک در حال بارگیری" در راهنمای TF بازرسی .

توجه داشته باشید که لبه ویژگی / نمودار به نام بعد از نام مورد استفاده در جسم پدر و مادر، نه نام متغیر. در نظر بگیرید CustomLayer در مثال زیر. متغیر CustomLayer.var با ذخیره "var" به عنوان بخشی از کلید، نه "var_a" .

class CustomLayer(keras.layers.Layer):
    def __init__(self, a):
        self.var = tf.Variable(a, name="var_a")


layer = CustomLayer(5)
layer_ckpt = tf.train.Checkpoint(layer=layer).save("custom_layer")

ckpt_reader = tf.train.load_checkpoint(layer_ckpt)

ckpt_reader.get_variable_to_dtype_map()
{'save_counter/.ATTRIBUTES/VARIABLE_VALUE': tf.int64,
 '_CHECKPOINTABLE_OBJECT_GRAPH': tf.string,
 'layer/var/.ATTRIBUTES/VARIABLE_VALUE': tf.int32}

مثال آموزش انتقال

اساسا، تا زمانی که دو مدل دارای معماری یکسانی باشند، می‌توانند نقطه بازرسی یکسانی را به اشتراک بگذارند.

مثال:

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

# Extract a portion of the functional model defined in the Setup section.
# The following lines produce a new model that excludes the final output
# layer of the functional model.
pretrained = keras.Model(
    functional_model.inputs, functional_model.layers[-1].input, name="pretrained_model"
)
# Randomly assign "trained" weights.
for w in pretrained.weights:
    w.assign(tf.random.normal(w.shape))
pretrained.save_weights("pretrained_ckpt")
pretrained.summary()

# Assume this is a separate program where only 'pretrained_ckpt' exists.
# Create a new functional model with a different output dimension.
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(5, name="predictions")(x)
model = keras.Model(inputs=inputs, outputs=outputs, name="new_model")

# Load the weights from pretrained_ckpt into model.
model.load_weights("pretrained_ckpt")

# Check that all of the pretrained weights have been loaded.
for a, b in zip(pretrained.weights, model.weights):
    np.testing.assert_allclose(a.numpy(), b.numpy())

print("\n", "-" * 50)
model.summary()

# Example 2: Sequential model
# Recreate the pretrained model, and load the saved weights.
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
pretrained_model = keras.Model(inputs=inputs, outputs=x, name="pretrained")

# Sequential example:
model = keras.Sequential([pretrained_model, keras.layers.Dense(5, name="predictions")])
model.summary()

pretrained_model.load_weights("pretrained_ckpt")

# Warning! Calling `model.load_weights('pretrained_ckpt')` won't throw an error,
# but will *not* work as expected. If you inspect the weights, you'll see that
# none of the weights will have loaded. `pretrained_model.load_weights()` is the
# correct method to call.
Model: "pretrained_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
digits (InputLayer)          [(None, 784)]             0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
=================================================================
Total params: 54,400
Trainable params: 54,400
Non-trainable params: 0
_________________________________________________________________

 --------------------------------------------------
Model: "new_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
digits (InputLayer)          [(None, 784)]             0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
_________________________________________________________________
predictions (Dense)          (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
pretrained (Functional)      (None, 64)                54400     
_________________________________________________________________
predictions (Dense)          (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca76990>

به طور کلی توصیه می شود برای ساخت مدل ها به همان API پایبند باشید. اگر بین Sequential و Functional، یا Functional و Subclassed و غیره جابجا می شوید، همیشه مدل از پیش آموزش دیده را بازسازی کنید و وزنه های از پیش آموزش دیده را در آن مدل بارگذاری کنید.

سوال بعدی این است که چگونه می توان وزن ها را ذخیره کرد و در مدل های مختلف بارگذاری کرد، اگر معماری مدل کاملاً متفاوت باشد؟ راه حل این است به استفاده از tf.train.Checkpoint به ذخیره و بازیابی لایه دقیق / متغیرها.

مثال:

# Create a subclassed model that essentially uses functional_model's first
# and last layers.
# First, save the weights of functional_model's first and last dense layers.
first_dense = functional_model.layers[1]
last_dense = functional_model.layers[-1]
ckpt_path = tf.train.Checkpoint(
    dense=first_dense, kernel=last_dense.kernel, bias=last_dense.bias
).save("ckpt")

# Define the subclassed model.
class ContrivedModel(keras.Model):
    def __init__(self):
        super(ContrivedModel, self).__init__()
        self.first_dense = keras.layers.Dense(64)
        self.kernel = self.add_variable("kernel", shape=(64, 10))
        self.bias = self.add_variable("bias", shape=(10,))

    def call(self, inputs):
        x = self.first_dense(inputs)
        return tf.matmul(x, self.kernel) + self.bias


model = ContrivedModel()
# Call model on inputs to create the variables of the dense layer.
_ = model(tf.ones((1, 784)))

# Create a Checkpoint with the same structure as before, and load the weights.
tf.train.Checkpoint(
    dense=model.first_dense, kernel=model.kernel, bias=model.bias
).restore(ckpt_path).assert_consumed()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/engine/base_layer.py:2223: UserWarning: `layer.add_variable` is deprecated and will be removed in a future version. Please use `layer.add_weight` method instead.
  warnings.warn('`layer.add_variable` is deprecated and '
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca6f390>

فرمت HDF5

فرمت HDF5 شامل وزن هایی است که بر اساس نام لایه ها گروه بندی شده اند. وزن لیست های مرتب شده توسط الحاق لیست وزن تربیت شدنی به لیست وزن غیر تربیت شدنی (همان هستند layer.weights ). بنابراین، اگر یک مدل دارای همان لایه‌ها و وضعیت‌های قابل آموزش باشد، می‌تواند از یک چک پوینت hdf5 استفاده کند.

مثال:

# Runnable example
sequential_model = keras.Sequential(
    [
        keras.Input(shape=(784,), name="digits"),
        keras.layers.Dense(64, activation="relu", name="dense_1"),
        keras.layers.Dense(64, activation="relu", name="dense_2"),
        keras.layers.Dense(10, name="predictions"),
    ]
)
sequential_model.save_weights("weights.h5")
sequential_model.load_weights("weights.h5")

توجه داشته باشید که تغییر layer.trainable ممکن است در یک متفاوتی layer.weights سفارش زمانی که مدل شامل لایه های تو در تو.

class NestedDenseLayer(keras.layers.Layer):
    def __init__(self, units, name=None):
        super(NestedDenseLayer, self).__init__(name=name)
        self.dense_1 = keras.layers.Dense(units, name="dense_1")
        self.dense_2 = keras.layers.Dense(units, name="dense_2")

    def call(self, inputs):
        return self.dense_2(self.dense_1(inputs))


nested_model = keras.Sequential([keras.Input((784,)), NestedDenseLayer(10, "nested")])
variable_names = [v.name for v in nested_model.weights]
print("variables: {}".format(variable_names))

print("\nChanging trainable status of one of the nested layers...")
nested_model.get_layer("nested").dense_1.trainable = False

variable_names_2 = [v.name for v in nested_model.weights]
print("\nvariables: {}".format(variable_names_2))
print("variable ordering changed:", variable_names != variable_names_2)
variables: ['nested/dense_1/kernel:0', 'nested/dense_1/bias:0', 'nested/dense_2/kernel:0', 'nested/dense_2/bias:0']

Changing trainable status of one of the nested layers...

variables: ['nested/dense_2/kernel:0', 'nested/dense_2/bias:0', 'nested/dense_1/kernel:0', 'nested/dense_1/bias:0']
variable ordering changed: True

مثال آموزش انتقالی

هنگام بارگیری وزنه های از پیش آموزش دیده از HDF5، توصیه می شود وزنه ها را در مدل اصلی چک پوینت بارگذاری کنید و سپس وزنه ها/لایه های مورد نظر را در یک مدل جدید استخراج کنید.

مثال:

def create_functional_model():
    inputs = keras.Input(shape=(784,), name="digits")
    x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
    x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
    outputs = keras.layers.Dense(10, name="predictions")(x)
    return keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")


functional_model = create_functional_model()
functional_model.save_weights("pretrained_weights.h5")

# In a separate program:
pretrained_model = create_functional_model()
pretrained_model.load_weights("pretrained_weights.h5")

# Create a new model by extracting layers from the original model:
extracted_layers = pretrained_model.layers[:-1]
extracted_layers.append(keras.layers.Dense(5, name="dense_3"))
model = keras.Sequential(extracted_layers)
model.summary()
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_3 (Dense)              (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________