Zapisane modele z TF Hub w TensorFlow 2

Format SavedModel TensorFlow 2 to zalecany sposób udostępniania wstępnie wytrenowanych modeli i fragmentów modeli w TensorFlow Hub. Zastępuje starszy format TF1 Hub i zawiera nowy zestaw interfejsów API.

Na tej stronie wyjaśniono, jak ponownie wykorzystać TF2 SavedModels w programie TensorFlow 2 z niskopoziomowym interfejsem API hub.load() i jego opakowaniem hub.KerasLayer . (Zazwyczaj hub.KerasLayer łączy się z innymi tf.keras.layers w celu zbudowania modelu Keras lub model_fn estymatora TF2). Te interfejsy API mogą również ładować starsze modele w formacie TF1 Hub, w pewnych granicach, patrz przewodnik po zgodności .

Użytkownicy TensorFlow 1 mogą zaktualizować do TF 1.15, a następnie korzystać z tych samych interfejsów API. Starsze wersje TF1 nie działają.

Korzystanie z SavedModels z TF Hub

Korzystanie z SavedModel w Keras

Keras to interfejs API wysokiego poziomu TensorFlow do tworzenia modeli głębokiego uczenia się poprzez komponowanie obiektów warstwy Keras. Biblioteka tensorflow_hub udostępnia klasę hub.KerasLayer , która jest inicjowana adresem URL (lub ścieżką systemu plików) SavedModel, a następnie udostępnia obliczenia z SavedModel, w tym jego wstępnie wyszkolone wagi.

Oto przykład użycia wstępnie wyszkolonego osadzania tekstu:

import tensorflow as tf
import tensorflow_hub as hub

hub_url = "https://tfhub.dev/google/nnlm-en-dim128/2"
embed = hub.KerasLayer(hub_url)
embeddings = embed(["A long sentence.", "single-word", "http://example.com"])
print(embeddings.shape, embeddings.dtype)

Na tej podstawie można zbudować klasyfikator tekstu w zwykły sposób Keras:

model = tf.keras.Sequential([
    embed,
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid"),
])

Colab dotyczący klasyfikacji tekstu jest kompletnym przykładem trenowania i oceniania takiego klasyfikatora.

Wagi modeli w hub.KerasLayer są domyślnie ustawione na niemożliwe do przeszkolenia. Zobacz sekcję dotyczącą dostrajania poniżej, aby dowiedzieć się, jak to zmienić. Wagi są współdzielone pomiędzy wszystkimi aplikacjami tego samego obiektu warstwy, jak zwykle w Keras.

Używanie zapisanego modelu w estymatorze

Użytkownicy interfejsu API estymatora TensorFlow do szkolenia rozproszonego mogą używać SavedModels z TF Hub, zapisując swój model_fn w kategoriach hub.KerasLayer wśród innych tf.keras.layers .

Za kulisami: pobieranie i buforowanie SavedModel

Użycie SavedModel z TensorFlow Hub (lub innych serwerów HTTPS, które implementują jego protokół hostingu ) powoduje pobranie go i dekompresję do lokalnego systemu plików, jeśli jeszcze go nie ma. Można ustawić zmienną środowiskową TFHUB_CACHE_DIR , aby zastąpić domyślną tymczasową lokalizację do buforowania pobranych i nieskompresowanych zapisanych modeli. Aby uzyskać szczegółowe informacje, zobacz Buforowanie .

Korzystanie z SavedModel w niskopoziomowym TensorFlow

Uchwyty modelowe

SavedModels można załadować z określonego handle , gdzie handle jest ścieżka systemu plików, prawidłowy adres URL modelu TFhub.dev (np. „https://tfhub.dev/…”). Adresy URL Kaggle Models odzwierciedlają uchwyty TFhub.dev zgodnie z naszymi Warunkami i licencją powiązaną z zasobami modelu, np. „https://www.kaggle.com/…”. Uchwyty z Kaggle Models są odpowiednikami odpowiadających im uchwytów TFhub.dev.

Funkcja hub.load(handle) pobiera i dekompresuje SavedModel (chyba że handle jest już ścieżką systemu plików), a następnie zwraca wynik załadowania go za pomocą wbudowanej funkcji TensorFlow tf.saved_model.load() . Dlatego hub.load() może obsłużyć każdy prawidłowy SavedModel (w przeciwieństwie do swojego poprzednika hub.Module dla TF1).

Temat zaawansowany: czego można oczekiwać od SavedModel po załadowaniu

W zależności od zawartości SavedModel wynik obj = hub.load(...) można wywołać na różne sposoby (jak wyjaśniono znacznie bardziej szczegółowo w Przewodniku SavedModel TensorFlow:

  • Podpisy obsługujące SavedModel (jeśli istnieją) są reprezentowane jako słownik konkretnych funkcji i można je wywołać w ten sposób tensors_out = obj.signatures["serving_default"](**tensors_in) , ze słownikami tensorów kluczowanymi przez odpowiednie dane wejściowe i wyjściowe nazwiska i z zastrzeżeniem ograniczeń dotyczących kształtu i typu podpisu.

  • Metody @tf.function -decorated zapisanego obiektu (jeśli istnieją) są przywracane jako obiekty tf.function, które można wywołać za pomocą wszystkich kombinacji argumentów Tensor i innych niż Tensor, dla których funkcja tf.function została prześledzona przed zapisaniem. W szczególności, jeśli istnieje metoda obj.__call__ z odpowiednimi śladami, sam obj można wywołać podobnie jak funkcję Pythona. Prosty przykład może wyglądać następująco: output_tensor = obj(input_tensor, training=False) .

Pozostawia to ogromną swobodę w zakresie interfejsów, które SavedModels może wdrożyć. Interfejs Reusable SavedModels dla obj ustanawia konwencje, dzięki którym kod klienta, w tym adaptery takie jak hub.KerasLayer , wie, jak używać SavedModel.

Niektóre SavedModels mogą nie być zgodne z tą konwencją, zwłaszcza całe modele, które nie są przeznaczone do ponownego wykorzystania w większych modelach i zawierają jedynie podpisy służące do obsługi.

Zmienne, które można wytrenować w SavedModel, są ponownie ładowane jako możliwe do wyszkolenia, a tf.GradientTape domyślnie je obejrzy. Zobacz sekcję dotyczącą dostrajania poniżej, aby poznać pewne zastrzeżenia i na początek rozważ uniknięcie tego. Nawet jeśli chcesz dostroić, możesz sprawdzić, czy obj.trainable_variables zaleca ponowne nauczenie tylko podzbioru pierwotnie możliwych do wytrenowania zmiennych.

Tworzenie zapisanych modeli dla TF Hub

Przegląd

SavedModel to standardowy format serializacji TensorFlow dla przeszkolonych modeli lub fragmentów modelu. Przechowuje wytrenowane wagi modelu wraz z dokładnymi operacjami TensorFlow w celu przeprowadzenia obliczeń. Można go używać niezależnie od kodu, który go utworzył. W szczególności można go ponownie wykorzystać w różnych interfejsach API wysokiego poziomu do budowania modeli, takich jak Keras, ponieważ operacje TensorFlow są ich wspólnym językiem podstawowym.

Oszczędzanie przed Kerasem

Począwszy od TensorFlow 2, tf.keras.Model.save() i tf.keras.models.save_model() domyślnie przyjmują format SavedModel (nie HDF5). Powstałe SavedModels, których można używać z hub.load() , hub.KerasLayer i podobnymi adapterami dla innych interfejsów API wysokiego poziomu, gdy tylko staną się dostępne.

Aby udostępnić kompletny model Keras, po prostu zapisz go za pomocą include_optimizer=False .

Aby udostępnić fragment Modelu Keras, uczyń go samym w sobie Modelem, a następnie zapisz go. Możesz albo ułożyć kod w ten sposób od początku....

piece_to_share = tf.keras.Model(...)
full_model = tf.keras.Sequential([piece_to_share, ...])
full_model.fit(...)
piece_to_share.save(...)

...lub wytnij fragment, który chcesz udostępnić po fakcie (jeśli pasuje do warstw całego modelu):

full_model = tf.keras.Model(...)
sharing_input = full_model.get_layer(...).get_output_at(0)
sharing_output = full_model.get_layer(...).get_output_at(0)
piece_to_share = tf.keras.Model(sharing_input, sharing_output)
piece_to_share.save(..., include_optimizer=False)

TensorFlow Models w GitHub wykorzystuje pierwsze podejście dla BERT (zobacz nlp/tools/export_tfhub_lib.py , zwróć uwagę na podział między core_model do eksportu i pretrainer do przywracania punktu kontrolnego) i drugie podejście do ResNet (zobacz dziedzictwo/image_classification/tfhub_export.py ).

Zapisywanie z niskiego poziomu TensorFlow

Wymaga to dobrej znajomości Przewodnika SavedModel TensorFlow.

Jeśli chcesz zapewnić coś więcej niż tylko podpis obsługujący, powinieneś zaimplementować interfejs Reusable SavedModel . Koncepcyjnie tak to wygląda

class MyMulModel(tf.train.Checkpoint):
  def __init__(self, v_init):
    super().__init__()
    self.v = tf.Variable(v_init)
    self.variables = [self.v]
    self.trainable_variables = [self.v]
    self.regularization_losses = [
        tf.function(input_signature=[])(lambda: 0.001 * self.v**2),
    ]

  @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
  def __call__(self, inputs):
    return tf.multiply(inputs, self.v)

tf.saved_model.save(MyMulModel(2.0), "/tmp/my_mul")

layer = hub.KerasLayer("/tmp/my_mul")
print(layer([10., 20.]))  # [20., 40.]
layer.trainable = True
print(layer.trainable_weights)  # [2.]
print(layer.losses)  # 0.004

Strojenie

Uczenie już wytrenowanych zmiennych zaimportowanego SavedModel wraz ze zmienną otaczającego go modelu nazywa się dostrajaniem SavedModel. Może to skutkować lepszą jakością, ale często powoduje, że szkolenie jest bardziej wymagające (może zająć więcej czasu, w większym stopniu zależeć od optymalizatora i jego hiperparametrów, zwiększać ryzyko nadmiernego dopasowania i wymagać powiększenia zbioru danych, szczególnie w przypadku CNN). Radzimy konsumentom SavedModel, aby zastanowili się nad dostrojeniem dopiero po ustaleniu dobrego programu szkoleniowego i tylko wtedy, gdy wydawca SavedModel to zaleca.

Dostrajanie zmienia „ciągłe” parametry modelu, które są trenowane. Nie zmienia to zakodowanych na stałe transformacji, takich jak tokenizacja wprowadzanego tekstu i mapowanie tokenów na odpowiadające im wpisy w macierzy osadzania.

Dla konsumentów SavedModel

Tworzenie koncentratora hub.KerasLayer like

layer = hub.KerasLayer(..., trainable=True)

umożliwia dostrojenie SavedModel załadowanego przez warstwę. Dodaje możliwe do trenowania ciężary i regulatory ciężaru zadeklarowane w SavedModel do modelu Keras i uruchamia obliczenia SavedModel w trybie treningowym (pomyśl o rezygnacji itp.).

Colab dotyczący klasyfikacji obrazów zawiera kompleksowy przykład z opcjonalnym dostrajaniem.

Ponowny eksport wyniku dostrajania

Zaawansowani użytkownicy mogą chcieć zapisać wyniki dostrajania z powrotem w SavedModel, którego można użyć zamiast oryginalnie załadowanego. Można to zrobić za pomocą kodu takiego jak

loaded_obj = hub.load("https://tfhub.dev/...")
hub_layer = hub.KerasLayer(loaded_obj, trainable=True, ...)

model = keras.Sequential([..., hub_layer, ...])
model.compile(...)
model.fit(...)

export_module_dir = os.path.join(os.getcwd(), "finetuned_model_export")
tf.saved_model.save(loaded_obj, export_module_dir)

Dla twórców SavedModel

Tworząc SavedModel do udostępniania w TensorFlow Hub, zastanów się z wyprzedzeniem, czy i w jaki sposób konsumenci powinni go dostroić, a także podaj wskazówki w dokumentacji.

Zapisywanie z modelu Keras powinno sprawić, że cała mechanika dostrajania będzie działać (oszczędzanie strat związanych z regularyzacją wagi, deklarowanie zmiennych możliwych do wyszkolenia, śledzenie __call__ zarówno dla training=True jak i training=False itp.)

Wybierz interfejs modelu, który dobrze współpracuje z przepływem gradientowym, np. logity wyjściowe zamiast prawdopodobieństw softmax lub przewidywań górnego k.

Jeśli w modelu zastosowano porzucanie, normalizację wsadową lub podobne techniki szkoleniowe obejmujące hiperparametry, ustaw je na wartości, które mają sens w przypadku wielu oczekiwanych problemów docelowych i rozmiarów partii. (W chwili pisania tego tekstu oszczędzanie w Keras nie ułatwia konsumentom dostosowania ich.)

Zapisywane są regulatory wagi na poszczególnych warstwach (wraz z ich współczynnikami siły regularyzacji), ale regularyzacja wagi z poziomu optymalizatora (np. tf.keras.optimizers.Ftrl.l1_regularization_strength=...) ) zostaje utracona. Odpowiednio poinformuj konsumentów o swoim SavedModel.