Utilisation des couches de prétraitement

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Prétraitement Keras

L'API des couches de prétraitement Keras permet aux développeurs de créer des pipelines de traitement d'entrée natifs Keras. Ces pipelines de traitement d'entrée peuvent être utilisés comme code de prétraitement indépendant dans des workflows non Keras, combinés directement avec des modèles Keras et exportés dans le cadre d'un Keras SavedModel.

Avec les couches de prétraitement Keras, vous pouvez créer et exporter des modèles véritablement de bout en bout : des modèles qui acceptent des images brutes ou des données structurées brutes en entrée ; modèles qui gèrent seuls la normalisation des caractéristiques ou l'indexation des valeurs des caractéristiques.

Prétraitement disponible

Prétraitement de texte

Prétraitement des caractéristiques numériques

Prétraitement des caractéristiques catégorielles

  • tf.keras.layers.CategoryEncoding : tours entiers caractéristiques nominales dans un chaud, multi-chaud, ou compter des représentations denses.
  • tf.keras.layers.Hashing : permet d' effectuer de hachage caractéristique catégorique, aussi connu comme le « truc de hachage ».
  • tf.keras.layers.StringLookup : catégorique de chaîne tours valeurs une représentation codée qui peut être lue par une Embedding couche ou Dense couche.
  • tf.keras.layers.IntegerLookup : tours entiers valeurs catégoriques en une représentation codée qui peut être lue par une Embedding couche ou Dense couche.

Prétraitement d'image

Ces couches servent à standardiser les entrées d'un modèle d'image.

Augmentation des données d'image

Ces couches appliquent des transformations d'augmentation aléatoires à un lot d'images. Ils ne sont actifs que pendant l'entraînement.

L' adapt() Méthode

Certaines couches de prétraitement ont un état interne qui peut être calculé sur la base d'un échantillon des données d'apprentissage. La liste des couches de prétraitement avec état est :

  • TextVectorization : titulaire d' un mappage entre des jetons de chaîne et des indices entiers
  • StringLookup et IntegerLookup : tenir une correspondance entre les valeurs d'entrée et des indices entiers.
  • Normalization : maintient la moyenne et l' écart - type des caractéristiques.
  • Discretization : contient des informations sur les limites du godet de valeur.

Fondamentalement, ces couches sont non trainable. Leur état n'est pas défini lors de l'entraînement ; il doit être réglé avant la formation, soit en les initialiser à partir d' une constante précalculée ou par « adapter » les données sur.

Vous définir l'état d'une couche de prétraitement en l' exposant à des données d'entraînement, par l' intermédiaire de l' adapt() méthode:

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

data = np.array([[0.1, 0.2, 0.3], [0.8, 0.9, 1.0], [1.5, 1.6, 1.7],])
layer = layers.Normalization()
layer.adapt(data)
normalized_data = layer(data)

print("Features mean: %.2f" % (normalized_data.numpy().mean()))
print("Features std: %.2f" % (normalized_data.numpy().std()))
Features mean: -0.00
Features std: 1.00

L' adapt() méthode prend soit une matrice Numpy ou un tf.data.Dataset objet. Dans le cas de StringLookup et TextVectorization , vous pouvez également passer une liste de chaînes:

data = [
    "ξεῖν᾽, ἦ τοι μὲν ὄνειροι ἀμήχανοι ἀκριτόμυθοι",
    "γίγνοντ᾽, οὐδέ τι πάντα τελείεται ἀνθρώποισι.",
    "δοιαὶ γάρ τε πύλαι ἀμενηνῶν εἰσὶν ὀνείρων:",
    "αἱ μὲν γὰρ κεράεσσι τετεύχαται, αἱ δ᾽ ἐλέφαντι:",
    "τῶν οἳ μέν κ᾽ ἔλθωσι διὰ πριστοῦ ἐλέφαντος,",
    "οἵ ῥ᾽ ἐλεφαίρονται, ἔπε᾽ ἀκράαντα φέροντες:",
    "οἱ δὲ διὰ ξεστῶν κεράων ἔλθωσι θύραζε,",
    "οἵ ῥ᾽ ἔτυμα κραίνουσι, βροτῶν ὅτε κέν τις ἴδηται.",
]
layer = layers.TextVectorization()
layer.adapt(data)
vectorized_text = layer(data)
print(vectorized_text)
tf.Tensor(
[[37 12 25  5  9 20 21  0  0]
 [51 34 27 33 29 18  0  0  0]
 [49 52 30 31 19 46 10  0  0]
 [ 7  5 50 43 28  7 47 17  0]
 [24 35 39 40  3  6 32 16  0]
 [ 4  2 15 14 22 23  0  0  0]
 [36 48  6 38 42  3 45  0  0]
 [ 4  2 13 41 53  8 44 26 11]], shape=(8, 9), dtype=int64)

De plus, les couches adaptables exposent toujours une option pour définir directement l'état via des arguments de constructeur ou une affectation de poids. Si les valeurs d'état sont destinés connus à couche le temps de construction, ou sont calculés à l' extérieur de l' adapt() appel, ils peuvent être réglés sans compter sur le calcul interne de la couche. Par exemple, si les fichiers de vocabulaire externes pour les TextVectorization , StringLookup ou IntegerLookup couches existent déjà, celles -ci peuvent être chargés directement dans les tables de recherche en passant un chemin vers le fichier de vocabulaire dans les arguments du constructeur de la couche.

Voici un exemple où nous instancier une StringLookup couche avec le vocabulaire précalculées:

vocab = ["a", "b", "c", "d"]
data = tf.constant([["a", "c", "d"], ["d", "z", "b"]])
layer = layers.StringLookup(vocabulary=vocab)
vectorized_data = layer(data)
print(vectorized_data)
tf.Tensor(
[[1 3 4]
 [4 0 2]], shape=(2, 3), dtype=int64)

Prétraitement des données avant le modèle ou à l'intérieur du modèle

Vous pouvez utiliser les couches de prétraitement de deux manières :

Option 1: Faites - les partie du modèle, comme ceci:

inputs = keras.Input(shape=input_shape)
x = preprocessing_layer(inputs)
outputs = rest_of_the_model(x)
model = keras.Model(inputs, outputs)

Avec cette option, le prétraitement se produira sur l'appareil, de manière synchrone avec le reste de l'exécution du modèle, ce qui signifie qu'il bénéficiera de l'accélération GPU. Si vous êtes une formation sur GPU, c'est la meilleure option pour la Normalization couche, pour toutes l' image et prétraiter couches d'augmentation des données.

Option 2: appliquer à votre tf.data.Dataset , de manière à obtenir un ensemble de données qui donne des lots de données pré - traitées, comme ceci:

dataset = dataset.map(lambda x, y: (preprocessing_layer(x), y))

Avec cette option, votre prétraitement se produira sur le processeur, de manière asynchrone, et sera mis en mémoire tampon avant d'entrer dans le modèle. De plus, si vous appelez dataset.prefetch(tf.data.AUTOTUNE) sur votre ensemble de données, le pré - traitement se produira efficacement en parallèle avec la formation:

dataset = dataset.map(lambda x, y: (preprocessing_layer(x), y))
dataset = dataset.prefetch(tf.data.AUTOTUNE)
model.fit(dataset, ...)

Ceci est la meilleure option pour TextVectorization , et toutes les couches prétraiter données structurées. Cela peut également être une bonne option si vous vous entraînez sur le processeur et que vous utilisez des couches de prétraitement d'image.

Lors de l' exécution sur TPU, vous devez toujours placer des couches dans le pré - traitement tf.data pipeline (à l'exception de la Normalization et Rescaling , qui fonctionnent très bien sur TPU et sont couramment utilisés comme la première couche est un modèle d'image).

Avantages du prétraitement à l'intérieur du modèle au moment de l'inférence

Même si vous optez pour l'option 2, vous souhaiterez peut-être exporter ultérieurement un modèle de bout en bout à inférence uniquement qui inclura les couches de prétraitement. La clé avantage à faire est que cela rend votre modèle portable et il aide à réduire la formation / service d' inclinaison .

Lorsque tous les prétraitements des données font partie du modèle, d'autres personnes peuvent charger et utiliser votre modèle sans avoir à savoir comment chaque fonctionnalité doit être encodée et normalisée. Votre modèle d'inférence sera capable de traiter des images brutes ou des données structurées brutes, et n'exigera pas que les utilisateurs du modèle connaissent les détails, par exemple le schéma de tokenisation utilisé pour le texte, le schéma d'indexation utilisé pour les caractéristiques catégorielles, qu'il s'agisse de valeurs de pixels d'image sont normalisés à [-1, +1] ou [0, 1] , etc. Ceci est particulièrement puissant si vous exportez votre modèle à un autre moment de l' exécution, comme TensorFlow.js: vous n'aurez pas à votre réimplémentez pré - traitement pipeline en JavaScript.

Si vous mettez d' abord vos couches de pré - traitement dans votre tf.data pipeline, vous pouvez exporter un modèle d'inférence que les paquets le pré - traitement. Instanciez simplement un nouveau modèle qui enchaîne vos couches de prétraitement et votre modèle d'entraînement :

inputs = keras.Input(shape=input_shape)
x = preprocessing_layer(inputs)
outputs = training_model(x)
inference_model = keras.Model(inputs, outputs)

Recettes rapides

Augmentation des données d'image

Notez que les couches d'augmentation de données d'image ne sont actives que pendant la formation ( de façon similaire à la Dropout couche).

from tensorflow import keras
from tensorflow.keras import layers

# Create a data augmentation stage with horizontal flipping, rotations, zooms
data_augmentation = keras.Sequential(
    [
        layers.RandomFlip("horizontal"),
        layers.RandomRotation(0.1),
        layers.RandomZoom(0.1),
    ]
)

# Load some data
(x_train, y_train), _ = keras.datasets.cifar10.load_data()
input_shape = x_train.shape[1:]
classes = 10

# Create a tf.data pipeline of augmented images (and their labels)
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.batch(16).map(lambda x, y: (data_augmentation(x), y))


# Create a model and train it on the augmented image data
inputs = keras.Input(shape=input_shape)
x = layers.Rescaling(1.0 / 255)(inputs)  # Rescale inputs
outputs = keras.applications.ResNet50(  # Add the rest of the model
    weights=None, input_shape=input_shape, classes=classes
)(x)
model = keras.Model(inputs, outputs)
model.compile(optimizer="rmsprop", loss="sparse_categorical_crossentropy")
model.fit(train_dataset, steps_per_epoch=5)
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 6s 0us/step
170508288/170498071 [==============================] - 6s 0us/step
5/5 [==============================] - 11s 44ms/step - loss: 8.8927
<keras.callbacks.History at 0x7f1c0c3f16d0>

Vous pouvez voir une configuration similaire en action dans l'exemple classification des images à partir de zéro .

Normalisation des caractéristiques numériques

# Load some data
(x_train, y_train), _ = keras.datasets.cifar10.load_data()
x_train = x_train.reshape((len(x_train), -1))
input_shape = x_train.shape[1:]
classes = 10

# Create a Normalization layer and set its internal state using the training data
normalizer = layers.Normalization()
normalizer.adapt(x_train)

# Create a model that include the normalization layer
inputs = keras.Input(shape=input_shape)
x = normalizer(inputs)
outputs = layers.Dense(classes, activation="softmax")(x)
model = keras.Model(inputs, outputs)

# Train the model
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
model.fit(x_train, y_train)
1563/1563 [==============================] - 3s 2ms/step - loss: 2.1304
<keras.callbacks.History at 0x7f1bc43f40d0>

Encodage des caractéristiques catégorielles de la chaîne via un encodage à chaud

# Define some toy data
data = tf.constant([["a"], ["b"], ["c"], ["b"], ["c"], ["a"]])

# Use StringLookup to build an index of the feature values and encode output.
lookup = layers.StringLookup(output_mode="one_hot")
lookup.adapt(data)

# Convert new test data (which includes unknown feature values)
test_data = tf.constant([["a"], ["b"], ["c"], ["d"], ["e"], [""]])
encoded_data = lookup(test_data)
print(encoded_data)
tf.Tensor(
[[0. 0. 0. 1.]
 [0. 0. 1. 0.]
 [0. 1. 0. 0.]
 [1. 0. 0. 0.]
 [1. 0. 0. 0.]
 [1. 0. 0. 0.]], shape=(6, 4), dtype=float32)

Notez que, ici, l' index 0 est réservé pour des contrôles hors-vocabulaire valeurs (valeurs qui ne sont pas vu lors de adapt() ).

Vous pouvez voir le StringLookup en action dans la classification des données structurées à partir de zéro par exemple.

Encodage de caractéristiques catégorielles entières via un encodage à chaud

# Define some toy data
data = tf.constant([[10], [20], [20], [10], [30], [0]])

# Use IntegerLookup to build an index of the feature values and encode output.
lookup = layers.IntegerLookup(output_mode="one_hot")
lookup.adapt(data)

# Convert new test data (which includes unknown feature values)
test_data = tf.constant([[10], [10], [20], [50], [60], [0]])
encoded_data = lookup(test_data)
print(encoded_data)
tf.Tensor(
[[0. 0. 1. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0.]
 [1. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1.]], shape=(6, 5), dtype=float32)

Notez que l' index 0 est réservé pour les valeurs manquantes (que vous devez spécifier la valeur 0), et l' indice 1 est réservé aux hors-vocabulaire valeurs (valeurs qui ne sont pas vu lors de adapt() ). Vous pouvez configurer cela en utilisant le mask_token et oov_token arguments du constructeur de IntegerLookup .

Vous pouvez voir le IntegerLookup en action dans l'exemple classification des données structurées à partir de zéro .

Application de l'astuce de hachage à une caractéristique catégorielle entière

Si vous avez une caractéristique catégorique qui peut prendre de nombreuses valeurs différentes (de l'ordre de 10e3 ou plus), où chaque valeur n'apparaît que quelques fois dans les données, il devient peu pratique et inefficace d'indexer et de coder à chaud les valeurs de caractéristique. Au lieu de cela, cela peut être une bonne idée d'appliquer le "truc de hachage": hachez les valeurs sur un vecteur de taille fixe. Cela permet de gérer la taille de l'espace de fonctionnalités et supprime le besoin d'une indexation explicite.

# Sample data: 10,000 random integers with values between 0 and 100,000
data = np.random.randint(0, 100000, size=(10000, 1))

# Use the Hashing layer to hash the values to the range [0, 64]
hasher = layers.Hashing(num_bins=64, salt=1337)

# Use the CategoryEncoding layer to multi-hot encode the hashed values
encoder = layers.CategoryEncoding(num_tokens=64, output_mode="multi_hot")
encoded_data = encoder(hasher(data))
print(encoded_data.shape)
(10000, 64)

Encodage du texte sous forme de séquence d'indices de jetons

Voici comment vous devriez préprocesseur texte à passer à une Embedding couche.

# Define some text data to adapt the layer
adapt_data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)

# Create a TextVectorization layer
text_vectorizer = layers.TextVectorization(output_mode="int")
# Index the vocabulary via `adapt()`
text_vectorizer.adapt(adapt_data)

# Try out the layer
print(
    "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(),
)

# Create a simple model
inputs = keras.Input(shape=(None,), dtype="int64")
x = layers.Embedding(input_dim=text_vectorizer.vocabulary_size(), output_dim=16)(inputs)
x = layers.GRU(8)(x)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

# Create a labeled dataset (which includes unknown tokens)
train_dataset = tf.data.Dataset.from_tensor_slices(
    (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0])
)

# Preprocess the string inputs, turning them into int sequences
train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y))
# Train the model on the int sequences
print("\nTraining model...")
model.compile(optimizer="rmsprop", loss="mse")
model.fit(train_dataset)

# For inference, you can export a model that accepts strings as input
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
outputs = model(x)
end_to_end_model = keras.Model(inputs, outputs)

# Call the end-to-end model on test data (which includes unknown tokens)
print("\nCalling end-to-end model on test string...")
test_data = tf.constant(["The one the other will absorb"])
test_output = end_to_end_model(test_data)
print("Model output:", test_output)
Encoded text:
 [[ 2 19 14  1  9  2  1]]

Training model...
1/1 [==============================] - 3s 3s/step - loss: 0.4776

Calling end-to-end model on test string...
Model output: tf.Tensor([[0.04233753]], shape=(1, 1), dtype=float32)

Vous pouvez voir la TextVectorization couche en action, combinée à un Embedding mode dans l'exemple classement de texte à partir de zéro .

Notez que lors de la formation d' un tel modèle, pour des performances optimales, vous devez toujours utiliser la TextVectorization couche dans le cadre de la canalisation d'entrée.

Encodage du texte sous forme de matrice dense de ngrams avec encodage multi-hot

Voici comment vous devriez préprocesseur texte à passer à une Dense couche.

# Define some text data to adapt the layer
adapt_data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)
# Instantiate TextVectorization with "multi_hot" output_mode
# and ngrams=2 (index all bigrams)
text_vectorizer = layers.TextVectorization(output_mode="multi_hot", ngrams=2)
# Index the bigrams via `adapt()`
text_vectorizer.adapt(adapt_data)

# Try out the layer
print(
    "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(),
)

# Create a simple model
inputs = keras.Input(shape=(text_vectorizer.vocabulary_size(),))
outputs = layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)

# Create a labeled dataset (which includes unknown tokens)
train_dataset = tf.data.Dataset.from_tensor_slices(
    (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0])
)

# Preprocess the string inputs, turning them into int sequences
train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y))
# Train the model on the int sequences
print("\nTraining model...")
model.compile(optimizer="rmsprop", loss="mse")
model.fit(train_dataset)

# For inference, you can export a model that accepts strings as input
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
outputs = model(x)
end_to_end_model = keras.Model(inputs, outputs)

# Call the end-to-end model on test data (which includes unknown tokens)
print("\nCalling end-to-end model on test string...")
test_data = tf.constant(["The one the other will absorb"])
test_output = end_to_end_model(test_data)
print("Model output:", test_output)
WARNING:tensorflow:5 out of the last 1567 calls to <function PreprocessingLayer.make_adapt_function.<locals>.adapt_step at 0x7f1b9c5c5290> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
Encoded text:
 [[1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 0. 0. 0. 0. 0.

  0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0. 0.]]

Training model...
1/1 [==============================] - 0s 231ms/step - loss: 1.0046

Calling end-to-end model on test string...
Model output: tf.Tensor([[-0.54753447]], shape=(1, 1), dtype=float32)

Encodage du texte sous forme de matrice dense de ngrams avec pondération TF-IDF

Ceci est une autre façon de texte pré - traitement avant de passer à une Dense couche.

# Define some text data to adapt the layer
adapt_data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)
# Instantiate TextVectorization with "tf-idf" output_mode
# (multi-hot with TF-IDF weighting) and ngrams=2 (index all bigrams)
text_vectorizer = layers.TextVectorization(output_mode="tf-idf", ngrams=2)
# Index the bigrams and learn the TF-IDF weights via `adapt()`

with tf.device("CPU"):
    # A bug that prevents this from running on GPU for now.
    text_vectorizer.adapt(adapt_data)

# Try out the layer
print(
    "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(),
)

# Create a simple model
inputs = keras.Input(shape=(text_vectorizer.vocabulary_size(),))
outputs = layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)

# Create a labeled dataset (which includes unknown tokens)
train_dataset = tf.data.Dataset.from_tensor_slices(
    (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0])
)

# Preprocess the string inputs, turning them into int sequences
train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y))
# Train the model on the int sequences
print("\nTraining model...")
model.compile(optimizer="rmsprop", loss="mse")
model.fit(train_dataset)

# For inference, you can export a model that accepts strings as input
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
outputs = model(x)
end_to_end_model = keras.Model(inputs, outputs)

# Call the end-to-end model on test data (which includes unknown tokens)
print("\nCalling end-to-end model on test string...")
test_data = tf.constant(["The one the other will absorb"])
test_output = end_to_end_model(test_data)
print("Model output:", test_output)
WARNING:tensorflow:6 out of the last 1568 calls to <function PreprocessingLayer.make_adapt_function.<locals>.adapt_step at 0x7f1b9f6eae60> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
Encoded text:
 [[5.461647  1.6945957 0.        0.        0.        0.        0.

  0.        0.        0.        0.        0.        0.        0.
  0.        0.        1.0986123 1.0986123 1.0986123 0.        0.
  0.        0.        0.        0.        0.        0.        0.
  1.0986123 0.        0.        0.        0.        0.        0.
  0.        1.0986123 1.0986123 0.        0.        0.       ]]

Training model...
1/1 [==============================] - 0s 239ms/step - loss: 4.4868

Calling end-to-end model on test string...
Model output: tf.Tensor([[0.25670475]], shape=(1, 1), dtype=float32)

Des pièges importants

Travailler avec des couches de recherche avec des vocabulaires très volumineux

Vous trouverez peut - être vous travailler avec un très grand vocabulaire dans un TextVectorization , une StringLookup couche ou une IntegerLookup couche. En règle générale, un vocabulaire supérieur à 500 Mo serait considéré comme « très volumineux ».

Dans ce cas, pour une meilleure performance, vous devriez éviter d' utiliser adapt() . Au lieu de cela, précalculez votre vocabulaire à l'avance (vous pouvez utiliser Apache Beam ou TF Transform pour cela) et stockez-le dans un fichier. Chargez ensuite le vocabulaire dans la couche au moment de la construction en passant le filepath comme le vocabulary argument.

En utilisant des couches sur une consultation pod TPU ou ParameterServerStrategy .

Il y a une question en suspens qui cause la performance à se dégrader lors de l' utilisation d' un TextVectorization , StringLookup ou IntegerLookup couche tandis que la formation sur une nacelle de TPU ou sur plusieurs machines via ParameterServerStrategy . Ce problème devrait être corrigé dans TensorFlow 2.7.