Lưu và tải các mô hình Keras

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Giới thiệu

Một mô hình Keras bao gồm nhiều thành phần:

  • Kiến trúc hoặc cấu hình, chỉ định các lớp mà mô hình chứa và cách chúng được kết nối.
  • Tập hợp các giá trị trọng số ("trạng thái của mô hình").
  • Trình tối ưu hóa (được xác định bằng cách biên dịch mô hình).
  • Một tập hợp các thiệt hại và số liệu (được xác định bằng cách biên dịch các mô hình hoặc gọi add_loss() hoặc add_metric() ).

API Keras giúp bạn có thể lưu tất cả những phần này vào đĩa cùng một lúc hoặc chỉ lưu một cách có chọn lọc một số trong số chúng:

  • Lưu mọi thứ vào một kho lưu trữ duy nhất ở định dạng TensorFlow SavedModel (hoặc ở định dạng Keras H5 cũ hơn). Đây là thông lệ tiêu chuẩn.
  • Chỉ lưu kiến ​​trúc / cấu hình, thường dưới dạng tệp JSON.
  • Chỉ lưu các giá trị trọng số. Điều này thường được sử dụng khi đào tạo mô hình.

Chúng ta hãy xem xét từng tùy chọn này. Khi nào bạn sẽ sử dụng cái này hay cái kia, và chúng hoạt động như thế nào?

Cách lưu và tải một mô hình

Nếu bạn chỉ có 10 giây để đọc hướng dẫn này, đây là những điều bạn cần biết.

Lưu mô hình Keras:

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

Đang tải lại mô hình:

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

Bây giờ, chúng ta hãy xem xét các chi tiết.

Thành lập

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

Lưu và tải toàn bộ mô hình

Bạn có thể lưu toàn bộ mô hình vào một hiện vật duy nhất. Nó sẽ bao gồm:

  • Cấu trúc / cấu hình của mô hình
  • Các giá trị trọng lượng của mô hình (được học trong quá trình đào tạo)
  • Thông tin tổng hợp của mô hình (nếu compile() được gọi là)
  • Trình tối ưu hóa và trạng thái của nó, nếu có (điều này cho phép bạn bắt đầu lại quá trình đào tạo ở nơi bạn đã rời đi)

API

Có hai định dạng mà bạn có thể sử dụng để lưu toàn bộ một mô hình vào đĩa: định dạng TensorFlow SavedModel,định dạng Keras H5 cũ. Định dạng được đề xuất là SavedModel. Đó là mặc định khi bạn sử dụng model.save() .

Bạn có thể chuyển sang định dạng H5 bằng cách:

  • Đi qua save_format='h5' để save() .
  • Đi qua một tên tập tin mà kết thúc trong .h5 hoặc .keras để save() .

Định dạng SavedModel

SavedModel là định dạng lưu toàn diện hơn giúp lưu kiến ​​trúc mô hình, trọng số và đồ thị con Tensorflow được theo dõi của các hàm gọi. Điều này cho phép Keras khôi phục cả các lớp tích hợp cũng như các đối tượng tùy chỉnh.

Thí dụ:

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 chứa những gì

Gọi model.save('my_model') tạo ra một thư mục có tên my_model , chứa những điều sau đây:

ls my_model
assets  keras_metadata.pb  saved_model.pb  variables

Kiến trúc mô hình, và cấu hình đào tạo (bao gồm cả tôi ưu hoa, thua lỗ, và chỉ số) được lưu trữ trong saved_model.pb . Các trọng số được lưu trong variables/ thư mục.

Để biết thông tin chi tiết về định dạng SavedModel, vui lòng xem hướng dẫn SavedModel (Định dạng SavedModel trên đĩa) .

Cách SavedModel xử lý các đối tượng tùy chỉnh

Khi lưu các mô hình và các lớp của nó, là định dạng lưu trữ SavedModel tên lớp, chức năng cuộc gọi, thua lỗ, và trọng lượng (và cấu hình, nếu được thực hiện). Hàm gọi xác định đồ thị tính toán của mô hình / lớp.

Trong trường hợp không có cấu hình mô hình / lớp, hàm gọi được sử dụng để tạo mô hình tồn tại giống như mô hình ban đầu có thể được huấn luyện, đánh giá và sử dụng để suy luận.

Tuy nhiên, nó luôn luôn là một thực hành tốt để xác định get_configfrom_config phương pháp khi viết một mô hình tùy chỉnh hoặc lớp lớp. Điều này cho phép bạn dễ dàng cập nhật tính toán sau này nếu cần. Xem phần về đối tượng Tuỳ chỉnh để biết thêm thông tin.

Thí dụ:

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>

Mô hình được nạp đầu tiên được nạp bằng cách sử dụng cấu hình và CustomModel lớp. Mô hình thứ hai được tải bằng cách tạo động lớp mô hình hoạt động giống như mô hình ban đầu.

Định cấu hình SavedModel

Mới trong TensoFlow 2.4 Đối số save_traces đã được thêm vào model.save , cho phép bạn chuyển đổi SavedModel chức năng truy tìm. Chức năng được lưu cho phép Keras các đối tượng tùy chỉnh tái tải mà không có sự definitons lớp ban đầu, vì vậy khi save_traces=False , tất cả các đối tượng tùy chỉnh phải đã xác định get_config / from_config phương pháp. Khi tải, các đối tượng tùy chỉnh phải được truyền cho custom_objects tranh cãi. save_traces=False làm giảm không gian đĩa được sử dụng bởi SavedModel và tiết kiệm thời gian.

Định dạng Keras H5

Keras cũng hỗ trợ lưu một file HDF5 đơn chứa cấu trúc của mô hình, trọng lượng giá trị, và compile() thông tin. Nó là một giải pháp thay thế trọng lượng nhẹ cho SavedModel.

Thí dụ:

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>

Hạn chế

So với định dạng SavedModel, có hai thứ không được đưa vào tệp H5:

  • Lỗ gắn ngoài và các số liệu bổ sung qua model.add_loss() & model.add_metric() sẽ không được lưu (không giống như SavedModel). Nếu bạn có những tổn thất & số liệu như vậy trên mô hình của mình và bạn muốn tiếp tục đào tạo, bạn cần phải tự cộng lại những tổn thất này sau khi tải mô hình. Lưu ý rằng điều này không áp dụng đối với thiệt hại / số liệu được tạo ra bên trong lớp qua self.add_loss() & self.add_metric() . Chừng nào các lớp được nạp, những mất mát và số liệu được lưu giữ, vì chúng là một phần của call phương pháp của lớp.
  • Đồ thị tính toán tùy chỉnh các đối tượng như các lớp tùy chỉnh không được bao gồm trong các tập tin đã lưu. Tại thời điểm tải, Keras sẽ cần quyền truy cập vào các lớp / hàm Python của các đối tượng này để xây dựng lại mô hình. Xem các đối tượng Tuỳ chỉnh .

Lưu kiến ​​trúc

Cấu hình (hoặc kiến ​​trúc) của mô hình chỉ định các lớp mà mô hình chứa và cách các lớp này được kết nối *. Nếu bạn có cấu hình của một mô hình, thì mô hình có thể được tạo với trạng thái mới khởi tạo cho các trọng số và không có thông tin biên dịch.

* Lưu ý rằng điều này chỉ áp dụng cho các mô hình được xác định bằng cách sử dụng ứng dụng chức năng hoặc Tuần tự không phải là mô hình phân lớp.

Cấu hình của mô hình tuần tự hoặc mô hình API chức năng

Các loại mô hình này là biểu đồ rõ ràng của các lớp: cấu hình của chúng luôn có sẵn ở dạng có cấu trúc.

API

get_config()from_config()

Gọi config = model.get_config() sẽ trả về một dict Python chứa cấu hình của mô hình. Các mô hình tương tự sau đó có thể được tái tạo qua Sequential.from_config(config) (đối với một Sequential mô hình) hoặc Model.from_config(config) (đối với một mô hình API chức năng).

Quy trình làm việc tương tự cũng hoạt động cho bất kỳ lớp nào có thể tuần tự hóa.

Ví dụ về lớp:

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

Ví dụ về mô hình tuần tự:

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

Ví dụ về mô hình chức năng:

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

Điều này tương tự get_config / from_config , ngoại trừ nó biến mô hình thành một chuỗi JSON, mà sau đó có thể được nạp mà không có lớp mô hình ban đầu. Nó cũng dành riêng cho các mô hình, nó không dành cho các lớp.

Thí dụ:

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

Đối tượng tùy chỉnh

Mô hình và lớp

Các kiến trúc của mô hình subclassed và các lớp được định nghĩa trong các phương pháp __init__call . Họ được coi là Python bytecode, mà không thể được đăng vào một cấu hình JSON-tương thích - bạn có thể thử serializing bytecode (ví dụ như thông qua pickle ), nhưng nó hoàn toàn không an toàn và có nghĩa là mô hình của bạn không thể được nạp vào một hệ thống khác nhau.

Để tiết kiệm / tải một mô hình với các lớp tùy chỉnh được xác định, hoặc một mô hình subclassed, bạn nên ghi đè lên get_config và tùy chọn from_config phương pháp. Ngoài ra, bạn nên sử dụng đăng ký đối tượng tùy chỉnh để Keras biết về nó.

Các chức năng tùy chỉnh

Chức năng tùy chỉnh định nghĩa (ví dụ mất kích hoạt hoặc khởi tạo) không cần một get_config phương pháp. Tên hàm đủ để tải miễn là nó được đăng ký như một đối tượng tùy chỉnh.

Chỉ tải biểu đồ TensorFlow

Có thể tải biểu đồ TensorFlow do Keras tạo ra. Nếu bạn làm như vậy, bạn sẽ không cần phải cung cấp bất kỳ custom_objects . Bạn có thể làm như thế này:

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

Lưu ý rằng phương pháp này có một số nhược điểm:

  • Vì lý do truy xuất nguồn gốc, bạn phải luôn có quyền truy cập vào các đối tượng tùy chỉnh đã được sử dụng. Bạn sẽ không muốn đưa vào sản xuất một mô hình mà bạn không thể tạo lại.
  • Các đối tượng được trả về bởi tf.saved_model.load không phải là một mô hình Keras. Vì vậy, nó không dễ sử dụng. Ví dụ, bạn sẽ không có quyền truy cập vào .predict() hoặc .fit()

Thậm chí nếu việc sử dụng nó không được khuyến khích, nó có thể giúp bạn nếu bạn đang ở trong một hoàn cảnh hiểm nghèo, ví dụ, nếu bạn bị mất mã của các đối tượng tùy chỉnh của bạn hoặc có vấn đề tải mô hình với tf.keras.models.load_model() .

Bạn có thể tìm hiểu thêm tại trang về tf.saved_model.load

Xác định các phương thức cấu hình

Thông số kỹ thuật:

  • get_config nên trả lại một cuốn từ điển JSON-serializable để tương thích với các Keras architecture- và API mô hình tiết kiệm.
  • from_config(config) ( classmethod ) phải trả lại một lớp hoặc mô hình đối tượng mới được tạo ra từ các config. Lợi nhuận thực hiện mặc định cls(**config) .

Thí dụ:

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

Đăng ký đối tượng tùy chỉnh

Keras giữ một ghi chú về lớp nào đã tạo cấu hình. Từ ví dụ trên, tf.keras.layers.serialize tạo ra một hình thức tuần tự của lớp tùy chỉnh:

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

Keras giữ một danh sách tổng thể của tất cả tích hợp trong lớp, mô hình, tôi ưu hoa, và các lớp hệ mét, được sử dụng để tìm ra lớp đúng lời kêu gọi from_config . Nếu lớp không thể được tìm thấy, sau đó là một lỗi được nâng lên ( Value Error: Unknown layer ). Có một số cách để đăng ký các lớp tùy chỉnh vào danh sách này:

  1. Thiết custom_objects luận trong hàm tải. (xem ví dụ trong phần trên "Định nghĩa các phương pháp cấu hình")
  2. tf.keras.utils.custom_object_scope hoặc tf.keras.utils.CustomObjectScope
  3. tf.keras.utils.register_keras_serializable

Ví dụ về lớp và chức năng tùy chỉnh

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)

Nhân bản mô hình trong bộ nhớ

Bạn cũng có thể làm trong bộ nhớ nhân bản của một mô hình thông qua tf.keras.models.clone_model() . Điều này tương đương với việc lấy cấu hình sau đó tạo lại mô hình từ cấu hình của nó (vì vậy nó không bảo toàn thông tin biên dịch hoặc các giá trị trọng số lớp).

Thí dụ:

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

Chỉ lưu và tải các giá trị trọng lượng của mô hình

Bạn có thể chọn chỉ lưu và tải trọng lượng của mô hình. Điều này có thể hữu ích nếu:

  • Bạn chỉ cần mô hình để suy luận: trong trường hợp này, bạn sẽ không cần phải khởi động lại quá trình đào tạo, vì vậy bạn không cần thông tin biên dịch hoặc trạng thái trình tối ưu hóa.
  • Bạn đang học chuyển giao: trong trường hợp này, bạn sẽ đào tạo một mô hình mới sử dụng lại trạng thái của một mô hình trước đó, vì vậy bạn không cần thông tin biên dịch của mô hình trước đó.

API để truyền trọng lượng trong bộ nhớ

Trọng lượng có thể được sao chép giữa các đối tượng khác nhau bằng cách sử dụng get_weightsset_weights :

Các ví dụ dưới đây.

Chuyển trọng số từ lớp này sang lớp khác, trong bộ nhớ

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

Chuyển trọng số từ mô hình này sang mô hình khác với kiến ​​trúc tương thích, trong bộ nhớ

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

Trường hợp của các lớp không trạng thái

Bởi vì các lớp không trạng thái không thay đổi thứ tự hoặc số lượng trọng lượng, các mô hình có thể có kiến ​​trúc tương thích ngay cả khi có thêm / thiếu các lớp không trạng thái.

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 để lưu trọng lượng vào đĩa và tải chúng trở lại

Trọng lượng có thể được lưu vào đĩa bằng cách gọi model.save_weights trong các định dạng sau:

  • Điểm kiểm tra TensorFlow
  • HDF5

Định dạng mặc định cho model.save_weights là TensorFlow trạm kiểm soát. Có hai cách để chỉ định định dạng lưu:

  1. save_format luận: Đặt giá trị cho save_format="tf" hoặc save_format="h5" .
  2. path lập luận: Nếu đường dẫn đầu với .h5 hoặc .hdf5 , sau đó định dạng HDF5 được sử dụng. Hậu tố khác sẽ dẫn đến một trạm kiểm soát TensorFlow trừ save_format được thiết lập.

Ngoài ra còn có một tùy chọn truy xuất trọng số dưới dạng các mảng numpy trong bộ nhớ. Mỗi API đều có ưu và nhược điểm được trình bày chi tiết bên dưới.

Định dạng điểm kiểm tra TF

Thí dụ:

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

Định dạng chi tiết

Định dạng Điểm kiểm tra TensorFlow lưu và khôi phục các trọng số bằng cách sử dụng tên thuộc tính đối tượng. Ví dụ, hãy xem xét tf.keras.layers.Dense lớp. Lớp chứa hai trọng lượng: dense.kerneldense.bias . Khi lớp được lưu vào tf định dạng, các trạm kiểm soát kết quả chứa các phím "kernel""bias" và giá trị trọng lượng tương ứng của họ. Để biết thêm thông tin, xem "Đang tải cơ" trong hướng dẫn sử TF Checkpoint .

Lưu ý rằng thuộc tính / graph cạnh được đặt tên theo tên sử dụng trong đối tượng phụ huynh, không phải là tên của biến. Hãy xem xét các CustomLayer trong ví dụ dưới đây. Biến CustomLayer.var được lưu với "var" như một phần của chìa khóa, không "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}

Chuyển giao ví dụ học tập

Về cơ bản, miễn là hai mô hình có cùng kiến ​​trúc, chúng có thể chia sẻ cùng một trạm kiểm soát.

Thí dụ:

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>

Thông thường, bạn nên sử dụng cùng một API để xây dựng mô hình. Nếu bạn chuyển đổi giữa Tuần tự và Chức năng, hoặc Chức năng và lớp con, v.v., thì hãy luôn xây dựng lại mô hình được đào tạo trước và tải các trọng số được đào tạo trước vào mô hình đó.

Câu hỏi tiếp theo là, làm thế nào trọng số có thể được lưu và tải vào các mô hình khác nhau nếu các kiến ​​trúc mô hình khá khác nhau? Các giải pháp là sử dụng tf.train.Checkpoint để lưu và khôi phục các lớp chính xác / biến.

Thí dụ:

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

Định dạng HDF5

Định dạng HDF5 chứa các trọng số được nhóm theo tên lớp. Các trọng số là danh sách có thứ bằng cách kết hợp danh sách các trọng khả năng huấn luyện vào danh sách các trọng không khả năng huấn luyện (giống như layer.weights ). Do đó, một mô hình có thể sử dụng điểm kiểm tra hdf5 nếu nó có cùng các lớp và trạng thái có thể đào tạo như đã lưu trong điểm kiểm tra.

Thí dụ:

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

Lưu ý rằng việc thay đổi layer.trainable có thể dẫn đến một khác nhau layer.weights đặt hàng khi model chứa các lớp lồng nhau.

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

Chuyển giao ví dụ học tập

Khi tải trọng lượng đã được tinh luyện trước từ HDF5, bạn nên tải trọng lượng vào mô hình đã kiểm tra ban đầu, sau đó trích xuất các trọng lượng / lớp mong muốn sang một mô hình mới.

Thí dụ:

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
_________________________________________________________________