Skip to content

Mise en œuvre d'un réseau neuronal personnalisé sur MNIST à l'aide de Tensorflow 2.0 ?

Bonjour utilisateur de notre site web, nous avons découvert la réponse à ce que vous cherchiez, continuez à lire et vous la trouverez un peu plus bas.

Solution :

Je me suis demandé par où commencer avec votre question multiple, et j'ai décidé de le faire avec une déclaration :

Votre code ne devrait définitivement pas ressembler à cela et n'est pas du tout proche des meilleures pratiques actuelles de Tensorflow.

Désolé, mais le déboguer étape par étape est une perte de temps pour tout le monde et ne serait bénéfique pour aucun de nous.

Maintenant, passons au troisième point :

  1. Est-ce qu'il y a autre chose dans mon code ci-dessous que je peux optimiser plus loin
    dans ce code comme peut-être faire usage de tensorflow 2.x @tf.function
    decorator etc.)

Oui, vous pouvez utiliser tensorflow2.0 fonctionnalités et il semble que vous les fuyez (tf.function décorateur n'est d'aucune utilité ici en fait, laissez-le pour l'instant).

Suivre les nouvelles directives atténuerait vos problèmes avec votre 5ème point également, à savoir :

  1. Je veux aussi de l'aide pour écrire ce code d'une manière plus généralisée afin que...
    je puisse facilement implémenter d'autres réseaux comme les ConvNets (i.e. Conv, MaxPool
    etc.) basés sur ce code facilement.

car il est conçu spécifiquement pour cela. Après une petite introduction, je vais essayer de vous présenter ces concepts en quelques étapes :

1. Divisez votre programme en parties logiques.

Tensorflow a fait beaucoup de mal quand il s'agit de la lisibilité du code ; tout ce qui est en tf1.x était généralement écrasé en un seul endroit, des globaux suivis de la définition d'une fonction suivie d'un autre globaux ou peut-être du chargement de données, en somme du désordre. Ce n'est pas vraiment la faute des développeurs car la conception du système encourageait ces actions.

Maintenant, dans tf2.0 le programmeur est encouragé à diviser son travail de manière similaire à la structure que l'on peut voir en pytorch, chainer et d'autres frameworks plus conviviaux.

1.1 Chargement des données

Vous étiez sur la bonne voie avec Tensorflow Datasets mais vous vous êtes détourné sans raison apparente.

Voici votre code avec un commentaire sur ce qui se passe :

# You already have tf.data.Dataset objects after load
(x_train, y_train), (x_test, y_test) = tfds.load('mnist', split=['train', 'test'], 
                                                  batch_size=-1, as_supervised=True)

# But you are reshaping them in a strange manner...
x_train = tf.reshape(x_train, shape=(x_train.shape[0], 784))
x_test  = tf.reshape(x_test, shape=(x_test.shape[0], 784))

# And building from slices...
ds_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# Unreadable rescaling (there are built-ins for that)

Vous pouvez facilement généraliser cette idée pour n'importe quel ensemble de données, placez-le dans un module séparé, disons datasets.py:

import tensorflow as tf
import tensorflow_datasets as tfds

class ImageDatasetCreator:
    @classmethod
    # More portable and readable than dividing by 255
    def _convert_image_dtype(cls, dataset):
        return dataset.map(
            lambda image, label: (
                tf.image.convert_image_dtype(image, tf.float32),
                label,
            )
        )

    def __init__(self, name: str, batch: int, cache: bool = True, split=None):
        # Load dataset, every dataset has default train, test split
        dataset = tfds.load(name, as_supervised=True, split=split)
        # Convert to float range
        try:
            self.train = ImageDatasetCreator._convert_image_dtype(dataset["train"])
            self.test = ImageDatasetCreator._convert_image_dtype(dataset["test"])
        except KeyError as exception:
            raise ValueError(
                f"Dataset {name} does not have train and test, write your own custom dataset handler."
            ) from exception

        if cache:
            self.train = self.train.cache()  # speed things up considerably
            self.test = self.test.cache()

        self.batch: int = batch

    def get_train(self):
        return self.train.shuffle().batch(self.batch).repeat()

    def get_test(self):
        return self.test.batch(self.batch).repeat()

Donc maintenant vous pouvez charger plus de mnist en utilisant une simple commande :

from datasets import ImageDatasetCreator

if __name__ == "__main__":
    dataloader = ImageDatasetCreator("mnist", batch=64, cache = True)
    train, test = dataloader.get_train(), dataloader.get_test()

Et vous pouvez utiliser n'importe quel nom autre que mnist que vous voulez pour charger les ensembles de données à partir de maintenant.

S'il vous plaît, arrêtez de faire tout ce qui est lié à l'apprentissage profond des scripts à une main, vous êtes un programmeur aussi..

1.2 Création de modèles

Depuis tf2.0 il existe deux façons conseillées de procéder en fonction de la complexité des modèles :

  • tensorflow.keras.models.Sequential - cette façon a été montrée par @Stewart_R, pas besoin de réitérer ses points. Utilisée pour les modèles les plus simples (vous devriez utiliser celle-ci avec votre feedforward).
  • Hériter de tensorflow.keras.Model et écrire un modèle personnalisé. Celui-ci devrait être utilisé lorsque vous avez une sorte de logique à l'intérieur de votre module ou qu'il est plus compliqué (des choses comme les ResNets, les réseaux multivoies, etc.). Dans l'ensemble plus lisible et personnalisable.

Votre Model a essayé de ressembler à quelque chose comme ça mais ça a encore dérapé ; backprop ne fait définitivement pas partie du modèle lui-même, tout comme loss ou accuracy, les séparer dans un autre module ou fonction, defo pas un membre !

Cela dit, codons le réseau en utilisant la deuxième approche (vous devriez placer ce code dans le module model.py par souci de concision). Avant cela, je vais coder YourDense couche prédictive à partir de zéro en héritant de tf.keras.Layers (celle-ci pourrait aller dans layers.py module) :

import tensorflow as tf

class YourDense(tf.keras.layers.Layer):
    def __init__(self, units):
        # It's Python 3, you don't have to specify super parents explicitly
        super().__init__()
        self.units = units

    # Use build to create variables, as shape can be inferred from previous layers
    # If you were to create layers in __init__, one would have to provide input_shape
    # (same as it occurs in PyTorch for example)
    def build(self, input_shape):
        # You could use different initializers here as well
        self.kernel = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        # You could define bias in __init__ as well as it's not input dependent
        self.bias = self.add_weight(shape=(self.units,), initializer="random_normal")
        # Oh, trainable=True is default

    def call(self, inputs):
        # Use overloaded operators instead of tf.add, better readability
        return tf.matmul(inputs, self.kernel) + self.bias

En ce qui concerne votre

  1. Comment ajouter une couche de Dropout et de normalisation de lot dans cette implémentation personnalisée ?
    personnalisée ? (c'est-à-dire le faire fonctionner à la fois pour le temps de formation et de test).

Je suppose que vous souhaitez créer une implémentation personnalisée de ces couches.
Si non, vous pouvez simplement importer from tensorflow.keras.layers import Dropout et l'utiliser où vous voulez comme @Leevo l'a souligné.
Dépôt inversé avec un comportement différent pendant train et test ci-dessous :

class CustomDropout(layers.Layer):
    def __init__(self, rate, **kwargs):
        super().__init__(**kwargs)
        self.rate = rate

    def call(self, inputs, training=None):
        if training:
            # You could simply create binary mask and multiply here
            return tf.nn.dropout(inputs, rate=self.rate)
        # You would need to multiply by dropout rate if you were to do that
        return inputs

Couches prises ici et modifiées pour mieux correspondre à l'objectif de mise en valeur.

Maintenant vous pouvez créer votre modèle finalement (simple double feedforward) :

import tensorflow as tf

from layers import YourDense

class Model(tf.keras.Model):
    def __init__(self):
        super().__init__()
        # Use Sequential here for readability
        self.network = tf.keras.Sequential(
            [YourDense(100), tf.keras.layers.ReLU(), YourDense(10)]
        )

    def call(self, inputs):
        # You can use non-parametric layers inside call as well
        flattened = tf.keras.layers.Flatten()(inputs)
        return self.network(flattened)

Ofc, vous devriez utiliser les built-ins autant que possible dans les implémentations générales.

Cette structure est assez extensible, donc la généralisation aux réseaux convolutifs, resnets, senets, quoi que ce soit devrait être faite via ce module..... Vous pouvez en lire plus à ce sujet ici.

Je pense que cela répond à votre 5ème point :

  1. Je veux aussi de l'aide pour écrire ce code d'une manière plus généralisée pour que
    Je peux facilement mettre en œuvre d'autres réseaux comme ConvNets (c'est-à-dire Conv, MaxPool
    etc.) basés sur ce code facilement.

Dernière chose, vous pouvez avoir à utiliser model.build(shape) afin de construire le graphe de votre modèle.

model.build((None, 28, 28, 1))

Ce serait pour MNIST 28x28x1 forme d'entrée, où None représente le lot.

1.3 Formation

Encore une fois, la formation pourrait se faire de deux façons distinctes :

  • Keras standard model.fit(dataset) - utile dans les tâches simples comme la classification
  • tf.GradientTape - des schémas de formation plus compliqués, l'exemple le plus marquant serait celui des réseaux adversariaux génératifs, où deux modèles optimisent des objectifs orthogonaux en jouant le jeu du minmax.

Comme l'a souligné @Leevo une fois de plus, si vous devez utiliser la deuxième façon, vous ne serez pas en mesure d'utiliser simplement les callbacks fournis par Keras, donc je conseillerais de s'en tenir à la première option lorsque cela est possible.

En théorie, vous pourriez utiliser les fonctions de callback manuellement comme suit . on_batch_begin() et d'autres en cas de besoin, mais ce serait encombrant et je ne suis pas sûr de la façon dont cela fonctionnerait.

Lorsqu'il s'agit de la première option, vous pouvez utiliser la fonction tf.data.Dataset directement avec fit. Le voici présenté à l'intérieur d'un autre module (de préférence train.py):

def train(
    model: tf.keras.Model,
    path: str,
    train: tf.data.Dataset,
    epochs: int,
    steps_per_epoch: int,
    validation: tf.data.Dataset,
    steps_per_validation: int,
    stopping_epochs: int,
    optimizer=tf.optimizers.Adam(),
):
    model.compile(
        optimizer=optimizer,
        # I used logits as output from the last layer, hence this
        loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=[tf.metrics.SparseCategoricalAccuracy()],
    )

    model.fit(
        train,
        epochs=epochs,
        steps_per_epoch=steps_per_epoch,
        validation_data=validation,
        validation_steps=steps_per_validation,
        callbacks=[
            # Tensorboard logging
            tf.keras.callbacks.TensorBoard(
                pathlib.Path("logs")
                / pathlib.Path(datetime.datetime.now().strftime("%Y%m%d-%H%M%S")),
                histogram_freq=1,
            ),
            # Early stopping with best weights preserving
            tf.keras.callbacks.EarlyStopping(
                monitor="val_sparse_categorical_accuracy",
                patience=stopping_epochs,
                restore_best_weights=True,
            ),
        ],
    )
    model.save(path)

Une approche plus compliquée est très similaire (presque un copier-coller) à celle de PyTorch boucles d'entraînement, donc si vous êtes familier avec ceux-ci, ils ne devraient pas poser beaucoup de problèmes.

Vous pouvez trouver des exemples tout au long de tf2.0 docs, par exemple ici ou ici.

2. Autres choses

2.1 Questions sans réponse

  1. Y a-t-il autre chose dans le code que je peux optimiser davantage dans
    ce code ? c.-à-d. (faire usage du décorateur tensorflow 2.x @tf.function
    etc.)

Ci-dessus transforme déjà le Modèle en graphes, donc je ne pense pas que vous ayez intérêt à l'appeler dans ce cas. Et l'optimisation prématurée est la racine de tous les maux, n'oubliez pas de mesurer votre code avant de le faire.

Vous gagneriez beaucoup plus avec une mise en cache appropriée des données (comme décrit au début du #1.1) et un bon pipeline plutôt que ceux-là.

  1. De plus, j'ai besoin d'un moyen d'extraire tous mes poids finaux pour toutes les couches
    après la formation afin que je puisse les tracer et vérifier leurs distributions. Pour
    vérifier des problèmes comme la disparition ou l'explosion du gradient.

Comme l'a souligné @Leevo ci-dessus,

weights = model.get_weights()

vous permettrait d'obtenir les poids. Vous pouvez les transformer en np.array et tracer en utilisant seaborn, matplotlib, analyser, vérifier ou tout ce que vous voulez.

2.2 Mise en commun

Dans l'ensemble, votre main.py (ou point d'entrée ou quelque chose de similaire) consisterait en ceci (plus ou moins) :

from dataset import ImageDatasetCreator
from model import Model
from train import train

# You could use argparse for things like batch, epochs etc.
if __name__ == "__main__":
    dataloader = ImageDatasetCreator("mnist", batch=64, cache=True)
    train, test = dataloader.get_train(), dataloader.get_test()
    model = Model()
    model.build((None, 28, 28, 1))
    train(
        model, train, path epochs, test, len(train) // batch, len(test) // batch, ...
    )  # provide necessary arguments appropriately
    # Do whatever you want with those
    weights = model.get_weights()

Oh, rappelez-vous que les fonctions ci-dessus ne sont pas à copier-coller et devraient être traitées plus comme une ligne directrice. Contactez-moi si vous avez des questions.

3. Questions à partir de commentaires

3.1 Comment initialiser les couches personnalisées et intégrées ?

3.1.1 TLDR ce que vous êtes sur le point de lire

  • Fonction d'initialisation de Poisson personnalisée, mais il faut... trois
    arguments
  • tf.keras.initalization L'API a besoin deux arguments (voir le dernier point de leur documentation), donc l'un est
    spécifié par l'intermédiaire de la lambda à l'intérieur de la couche personnalisée que nous avons écrite auparavant
  • Un biais optionnel pour la couche est ajouté, qui peut être désactivé avec
    booléen

Pourquoi est-ce si inutilement compliqué ? Pour montrer que dans tf2.0 vous pouvez enfin utiliser les fonctionnalités de Python., plus besoin de s'embêter avec les graphes, if au lieu de tf.cond etc.

3.1.2 Du TLDR à la mise en œuvre

Les initialisateurs de Keras peuvent être trouvés ici et la saveur de Tensorflow ici.

Veuillez noter les incohérences de l'API (lettres majuscules comme les classes, lettres minuscules avec soulignement comme les fonctions), en particulier dans. tf2.0, mais ce n'est pas le sujet.

Vous pouvez les utiliser en passant une chaîne de caractères (comme c'est fait en YourDense ci-dessus) ou pendant la création de l'objet.

Pour permettre une initialisation personnalisée dans vos couches personnalisées, vous pouvez simplement ajouter un argument supplémentaire au constructeur (tf.keras.Model La classe est toujours une classe Python et elle est __init__ doit être utilisé de la même manière que celui de Python).

Avant cela, je vais vous montrer comment créer une initialisation personnalisée :

# Poisson custom initialization because why not.
def my_dumb_init(shape, lam, dtype=None):
    return tf.squeeze(tf.random.poisson(shape, lam, dtype=dtype))

Remarquez, sa signature prend trois arguments, alors qu'elle devrait prendre... (shape, dtype) seulement. Néanmoins, on peut "corriger" cela facilement en créant sa propre couche, comme celle ci-dessous (étendue YourLinear):

import typing

import tensorflow as tf

class YourDense(tf.keras.layers.Layer):
    # It's still Python, use it as Python, that's the point of tf.2.0
    @classmethod
    def register_initialization(cls, initializer):
        # Set defaults if init not provided by user
        if initializer is None:
            # let's make the signature proper for init in tf.keras
            return lambda shape, dtype: my_dumb_init(shape, 1, dtype)
        return initializer

    def __init__(
        self,
        units: int,
        bias: bool = True,
        # can be string or callable, some typing info added as well...
        kernel_initializer: typing.Union[str, typing.Callable] = None,
        bias_initializer: typing.Union[str, typing.Callable] = None,
    ):
        super().__init__()
        self.units: int = units
        self.kernel_initializer = YourDense.register_initialization(kernel_initializer)
        if bias:
            self.bias_initializer = YourDense.register_initialization(bias_initializer)
        else:
            self.bias_initializer = None

    def build(self, input_shape):
        # Simply pass your init here
        self.kernel = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer=self.kernel_initializer,
            trainable=True,
        )
        if self.bias_initializer is not None:
            self.bias = self.add_weight(
                shape=(self.units,), initializer=self.bias_initializer
            )
        else:
            self.bias = None

    def call(self, inputs):
        weights = tf.matmul(inputs, self.kernel)
        if self.bias is not None:
            return weights + self.bias

J'ai ajouté my_dumb_initialization comme valeur par défaut (si l'utilisateur n'en fournit pas) et rendu le biais optionnel avec bias argument. Notez que vous pouvez utiliser if librement tant qu'il n'est pas dépendant des données. S'il l'est (ou s'il dépend de tf.Tensor d'une manière ou d'une autre), il faut utiliser @tf.function qui modifie le flux de Python vers le flux tensorflow contrepartie (par exemple if à tf.cond).

Voir ici pour en savoir plus sur l'autographe, c'est très facile à suivre.

Si vous voulez incorporer les changements d'initialisateur ci-dessus dans votre modèle, vous devez créer l'objet approprié et c'est tout.

... # Previous of code Model here
self.network = tf.keras.Sequential(
    [
        YourDense(100, bias=False, kernel_initializer="lecun_uniform"),
        tf.keras.layers.ReLU(),
        YourDense(10, bias_initializer=tf.initializers.Ones()),
    ]
)
... # and the same afterwards

Avec l'intégré tf.keras.layers.Dense layers, on peut faire la même chose (les noms des arguments diffèrent, mais l'idée tient).

3.2 Différenciation automatique utilisant tf.GradientTape

3.2.1 Introduction

Point de tf.GradientTape est de permettre aux utilisateurs le flux de contrôle Python normal et le calcul du gradient des variables par rapport à une autre variable.

Exemple repris d'ici mais cassé en morceaux séparés :

def f(x, y):
  output = 1.0
  for i in range(y):
    if i > 1 and i < 5:
      output = tf.multiply(output, x)
  return output

Fonction python normale avec for et if déclarations de contrôle de flux

def grad(x, y):
  with tf.GradientTape() as t:
    t.watch(x)
    out = f(x, y)
  return t.gradient(out, x)

En utilisant la bande de gradient vous pouvez enregistrer toutes les opérations sur Tensors (ainsi que leurs états intermédiaires) et le "jouer" à l'envers (effectuer une différenciation arrière automatique en utilisant la règle de chaing).

Chaque Tensor à l'intérieur de tf.GradientTape() gestionnaire de contexte est enregistré automatiquement. Si un certain Tensor est hors de portée, utiliser watch() comme on peut le voir ci-dessus.

Enfin, le gradient de output par rapport à x (l'entrée est renvoyée).

3.2.2 Connexion avec l'apprentissage profond

Ce qui a été décrit ci-dessus est backpropagation algorithme. Les gradients par rapport (aux) sorties sont calculés pour chaque nœud du réseau (ou plutôt pour chaque couche). Ces gradients sont ensuite utilisés par divers optimiseurs pour effectuer des corrections et ainsi de suite.

Continuons et supposons que vous avez votre tf.keras.Model, instance d'optimiseur, tf.data.Dataset et la fonction de perte déjà configurés.

On peut définir une Trainer classe qui effectuera l'entraînement à notre place. Veuillez lire les commentaires dans le code en cas de doute.:

class Trainer:
    def __init__(self, model, optimizer, loss_function):
        self.model = model
        self.loss_function = loss_function
        self.optimizer = optimizer
        # You could pass custom metrics in constructor
        # and adjust train_step and test_step accordingly
        self.train_loss = tf.keras.metrics.Mean(name="train_loss")
        self.test_loss = tf.keras.metrics.Mean(name="train_loss")

    def train_step(self, x, y):
        # Setup tape
        with tf.GradientTape() as tape:
            # Get current predictions of network
            y_pred = self.model(x)
            # Calculate loss generated by predictions
            loss = self.loss_function(y, y_pred)
        # Get gradients of loss w.r.t. EVERY trainable variable (iterable returned)
        gradients = tape.gradient(loss, self.model.trainable_variables)
        # Change trainable variable values according to gradient by applying optimizer policy
        self.optimizer.apply_gradients(zip(gradients, self.model.trainable_variables))
        # Record loss of current step
        self.train_loss(loss)

    def train(self, dataset):
        # For N epochs iterate over dataset and perform train steps each time
        for x, y in dataset:
            self.train_step(x, y)

    def test_step(self, x, y):
        # Record test loss separately
        self.test_loss(self.loss_function(y, self.model(x)))

    def test(self, dataset):
        # Iterate over whole dataset
        for x, y in dataset:
            self.test_step(x, y)

    def __str__(self):
        # You need Python 3.7 with f-string support
        # Just return metrics
        return f"Loss: {self.train_loss.result()}, Test Loss: {self.test_loss.result()}"

Maintenant, vous pourriez utiliser cette classe dans votre code vraiment simplement comme ceci :

EPOCHS = 5

# model, optimizer, loss defined beforehand
trainer = Trainer(model, optimizer, loss)
for _ in range(EPOCHS):
    trainer.train(train_dataset) # Same for training and test datasets
    trainer.test(test_dataset)
    print(f"Epoch {epoch}: {trainer})")

L'impression vous indiquerait la perte de formation et de test pour chaque époque. Vous pouvez mélanger la formation et le test comme vous le souhaitez (par exemple, 5 époques pour la formation et 1 test), vous pourriez ajouter différentes métriques, etc.

Voir ici si vous voulez une approche orientée non-OOP (IMO moins lisible, mais à chacun son métier).

En outre, s'il y a quelque chose que je pourrais améliorer dans le code, faites-le moi savoir.
aussi bien.

Embrassez l'API de haut niveau pour quelque chose comme ça. Vous pouvez le faire en quelques lignes de code et c'est beaucoup plus facile à déboguer, à lire et à raisonner :

(x_train, y_train), (x_test, y_test) = tfds.load('mnist', split=['train', 'test'], 
                                                  batch_size=-1, as_supervised=True)

x_train = tf.cast(tf.reshape(x_train, shape=(x_train.shape[0], 784)), tf.float32)
x_test  = tf.cast(tf.reshape(x_test, shape=(x_test.shape[0], 784)), tf.float32)

model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(512, activation='sigmoid'),
  tf.keras.layers.Dense(256, activation='sigmoid'),
  tf.keras.layers.Dense(10, activation='softmax')
])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

J'ai essayé d'écrire une implémentation personnalisée d'un réseau neuronal basique avec
deux couches cachées sur le jeu de données MNIST en utilisant tensorflow 2.0 beta mais je ne suis pas sûr de ce qui a mal tourné ici.
Je ne suis pas sûr de ce qui s'est passé ici, mais ma perte de formation et la précision semble rester bloquée à 1,5 et autour de 1,5.
rester bloquées à 1,5 et autour de 85 respectivement.

Où se trouve la partie formation ? L'entraînement des modèles TF 2.0 soit la syntaxe de Keras ou... Exécution ardente avec tf.GradientTape(). Pouvez-vous coller le code avec les couches conv et dense, et comment vous l'avez formé ?


D'autres questions :

1) Comment ajouter une couche de Dropout dans cette implémentation personnalisée ? i.e.
(le faire fonctionner à la fois pour le temps de formation et de test).

Vous pouvez ajouter une couche Dropout() avec :

from tensorflow.keras.layers import Dropout

Et ensuite vous l'insérez dans un modèle Sequential() juste avec :

Dropout(dprob)     # where dprob = dropout probability

2) Comment ajouter la normalisation par lot dans ce code ?

Même chose que précédemment, avec :

from tensorflow.keras.layers import BatchNormalization

Le choix de pour mettre batchnorm dans le modèle, eh bien, c'est à vous de voir. Il n'y a pas de règle du pouce, je vous suggère de faire des expériences. Avec ML, c'est toujours un processus d'essais et d'erreurs.


3) Comment puis-je utiliser des callbacks dans ce code ? c'est à dire (en faisant usage de
EarlyStopping et ModelCheckpoint callbacks).

Si vous vous entraînez en utilisant la syntaxe de Keras, vous pouvez simplement utiliser cela. Veuillez consulter ce tutoriel très complet sur la façon de l'utiliser. Cela ne prend que quelques lignes de code.
Si vous exécutez un modèle dans Exécution impatiente, vous devez mettre en œuvre ces techniques vous-même, avec votre propre code. C'est plus complexe, mais cela vous donne aussi plus de liberté dans la mise en œuvre.


4) Y a-t-il autre chose dans le code que je peux optimiser davantage dans
ce code ? c'est-à-dire (utiliser le décorateur de fonction @tf.function de tensorflow 2.x
etc.)

Cela dépend . Si vous utilisez la syntaxe Keras, je ne pense pas que vous ayez besoin d'en rajouter. Dans le cas où vous entraînez le modèle dans l'exécution Eager, alors je vous suggérerais d'utiliser la fonction @tf.function sur certaines fonctions pour accélérer un peu.
Vous pouvez voir un exemple pratique de TF 2.0 sur la façon d'utiliser le décorateur dans ce carnet de notes.

A part cela, je vous suggère de jouer avec techniques de régularisation telles que les initialisations de poids, la perte L1-L2, etc.


5) J'ai également besoin d'un moyen d'extraire tous mes poids finaux pour toutes les couches
après la formation afin que je puisse les tracer et vérifier leurs distributions. Pour
vérifier des problèmes comme la disparition ou l'explosion du gradient.

Une fois que le modèle est formé, vous pouvez extraire ses poids avec :

weights = model.get_weights()

ou :

weights = model.trainable_weights

Si vous voulez ne garder que ceux qui sont entraînables.


6) Je veux aussi de l'aide pour écrire ce code d'une manière plus généralisée pour que
Je peux facilement mettre en œuvre d'autres réseaux comme le réseau convolutif (i.e.
Conv, MaxPool etc.) basé sur ce code facilement.

Vous pouvez emballer tout votre code dans une fonction, puis . À la fin de ce Notebook, j'ai fait quelque chose comme ceci (c'est pour un NN feed-forward, qui est beaucoup plus simple, mais c'est un début et vous pouvez changer le code selon vos besoins).

---

UPDATE:

Veuillez consulter mon implémentation TensorFlow 2.0 d'un classificateur CNN. Cela pourrait être un indice utile : il est entraîné sur le... Mode MNIST ce qui le rend très similaire à votre tâche.

Si vous avez encore un empêchement et une disposition à affiner notre division, vous êtes en mesure d'écrire une critique et nous l'étudierons avec plaisir.



Utilisez notre moteur de recherche

Ricerca
Generic filters

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.