Neural Turing Machine : Guide Complet — Mémoire Externe Différentiable

142-neural-turing-machine

Neural Turing Machine : Guide Complet — Mémoire Externe Différentiable

Résumé

La Neural Turing Machine (NTM) est une architecture neuronale révolutionnaire proposée par Alex Graves, Greg Wayne et Ivo Danihelka chez DeepMind en 2014. Elle étend les capacités des réseaux de neurones récurrents en leur ajoutant une mémoire externe adressable, rendant possible l’apprentissage de tâches algorithmiques qui dépassaient jusque-là les capacités du deep learning classique : copie de séquences, association, tri, et même l’exécution de programmes simples.

Le principe fondamental est élégant : un contrôleur neuronal (généralement un LSTM ou un MLP) interagit avec une matrice mémoire externalisée via des têtes de lecture et d’écriture entièrement différentiables. Cette différentiabilité permet l’entraînement par rétropropagation classique — le gradient circule à travers les opérations d’attention, ce qui distingue radicalement la NTM des mémoires externes classiques non différentiables.

La NTM a ensuite inspiré le Differentiable Neural Computer (DNC) de DeepMind (2016), qui ajoute des mécanismes de liaison temporelle et d’allocation dynamique de mémoire. Ensemble, ces architectures constituent une lignée fondamentale de recherche en deep learning, préfigurant les mécanismes d’attention qui domineront le domaine quelques années plus tard.

Principe Mathématique

Une Neural Turing Machine se compose de deux éléments fondamentaux :

Architecture globale

NTM = contrôleur neuronal + matrice mémoire M ∈ ℝ^{N×W}

N est le nombre d’emplacements mémoire et W la largeur de chaque vecteur mémoire. Le contrôleur peut être un réseau récurrent (LSTM, GRU) ou un perceptron multicouche (MLP). À chaque pas de temps t, le contrôleur :

  1. Reçoit une entrée externe xₜ
  2. Lit des vecteurs depuis la mémoire via les têtes de lecture
  3. Produit une sortie yₜ et des paramètres de lecture/écriture
  4. Modifie la mémoire via les têtes d’écriture

Mécanisme de lecture

La lecture s’effectue par attention pondérée sur les emplacements mémoire :

rₜ = Σᵢ wₜ(i) · Mₜ(i)

wₜ est un vecteur de poids d’attention de dimension N, normalisé par softmax (Σᵢ wₜ(i) = 1), et Mₜ(i) désigne le i-ème vecteur mémoire de largeur W. Ce mécanisme de lecture douce (soft reading) est ce qui rend l’opération différentiable : au lieu de lire un seul emplacement discret, on lit une combinaison pondérée de tous les emplacements, permettant au gradient de circuler vers chaque position mémoire.

Mécanisme d’écriture

L’écriture modifie la mémoire en deux phases : effacement puis ajout.

Phase d’effacement :

M̃ₜ(i) = Mₜ₋₁(i) · (1 − wₜ(i) · eₜ)

eₜ ∈ [0,1]^W est le vecteur d’effacement généré par le contrôleur. Le terme (1 − wₜ(i) · eₜ) permet d’effacer sélectivement certaines dimensions de l’emplacement i, proportionnellement au poids d’attention wₜ(i).

Phase d’ajout :

Mₜ(i) = M̃ₜ(i) + wₜ(i) · aₜ

aₜ ∈ ℝ^W est le vecteur d’ajout. L’écriture complète combine les deux :

Mₜ(i) = Mₜ₋₁(i) · (1 − wₜ(i) · eₜ) + wₜ(i) · aₜ

Cette formulation garantit que seuls les emplacements auxquels on porte attention sont modifiés, et que la modification est proportionnelle à cette attention.

Adressage par contenu

L’adressage par contenu permet de retrouver un emplacement mémoire en fonction de sa similarité avec un key vector émis par le contrôleur :

wᶜ(i) = softmax( cos(kₜ, Mₜ(i)) / β )

kₜ ∈ ℝ^W est le vecteur-clé produit par le contrôleur, β > 0 est un paramètre de netteté (sharpness) qui contrôle la focalisation de l’attention, et cos(·,·) désigne la similarité cosinus :

cos(kₜ, Mₜ(i)) = (kₜ · Mₜ(i)) / (‖kₜ‖ · ‖Mₜ(i)‖)

Un β élevé concentre l’attention sur l’emplacement le plus similaire ; un β faible produit une attention plus diffuse.

Adressage par location

L’adressage par location permet de se déplacer séquentiellement dans la mémoire, indispensable pour des tâches ordonnées comme la copie de séquences. Il s’opère en trois sous-étapes sur le vecteur de poids précédent wₜ₋₁ :

1. Interpolation (gating) :

w̃ₜ = gₜ · wᶜₜ + (1 − gₜ) · wₜ₋₁

où gₜ ∈ [0,1] détermine le mélange entre l’adressage par contenu et la position précédente.

2. Déplacement circulaire (convolutional shift) :

ŵₜ(j) = Σₖ w̃ₜ(j − k) · sₜ(k)

sₜ est un noyau de décalage de dimension impaire (typiquement 3), et l’indice est pris modulo N (rotation circulaire). Ce déplacement permet de se focaliser sur l’emplacement adjacent précédent ou suivant.

3. Nettoyage (sharpening) :

wₜ(i) = ŵₜ(i)^γ / Σⱼ ŵₜ(j)^γ

où γ ≥ 1 est un paramètre de netteté qui empêche le vecteur de poids de devenir trop diffus à force de convolutions successives.

Flux complet à chaque pas de temps

Le déroulement complet à chaque itération t est le suivant :

Entrée xₜ → Contrôleur → Paramètres de lecture/écriture
                        ↓
            wₜ(content) via similarité cosinus
                        ↓
            wₜ(location) via shift circulaire
                        ↓
            Lecture: rₜ = Σᵢ wₜ(i) · Mₜ(i)
                        ↓
            Écriture: Mₜ(i) = Mₜ₋₁(i)·(1−wₜ(i)·eₜ) + wₜ(i)·aₜ
                        ↓
            Sortie yₜ

Intuition : La Différence Entre Mémoriser et Écrire

Pour comprendre pourquoi la NTM représente un saut conceptuel, considérons cette analogie : un réseau de neurones classique a sa mémoire intégrée dans ses poids — comme un musicien qui joue entièrement de mémoire. Il peut reproduire ce qu’il a appris pendant l’entraînement, mais il ne peut pas mémoriser de nouvelles informations pendant l’exécution. Si vous lui présentez une séquence qu’il n’a jamais vue, il doit la traiter en temps réel sans pouvoir la retenir.

Un NTM, lui, possède une mémoire externe — comme un pianiste qui lit une partition. Le contrôleur neuronal est le pianiste : il sait jouer, il connaît la technique. Mais la partition externe, c’est la mémoire M. Le pianiste peut :

  • Écrire de nouvelles notes : quand il apprend quelque chose de nouveau pendant la séquence, il l’inscrit sur la partition (tête d’écriture)
  • Relire plus tard : quand il a besoin de cette information, il retourne la trouver à l’emplacement approprié (tête de lecture)
  • Modifier ses notes : il peut gommer une partie et écrire par-dessus (effacement + ajout)

C’est la différence fondamentale entre mémoriser un numéro de téléphone dans sa tête et l’écrire sur un Post-it. Dans le premier cas, la capacité est limitée et fragile. Dans le second, on peut stocker beaucoup plus, retrouver l’information précisément, et la modifier à volonté.

Cette séparation entre capacité de traitement (le contrôleur) et capacité de stockage (la mémoire) est exactement ce qui permet aux NTM de généraliser à des longueurs de séquences jamais vues pendant l’entraînement — une faiblesse notoire des LSTM et GRU classiques.

Implémentation Python avec PyTorch

Architecture de base d’une NTM simplifiée

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np


class SoftAttention(nn.Module):
    """
    Mécanisme d'attention douce pour les têtes de lecture/écriture.
    Combine adressage par contenu et par location.
    """
    def __init__(self, memory_width, shift_range=1):
        super().__init__()
        self.memory_width = memory_width
        self.shift_range = shift_range

    def content_addressing(self, key, memory, beta):
        """
        Adressage par contenu : similarité cosinus normalisée.

        Args:
            key: tenseur de forme (batch_size, memory_width)
            memory: tenseur de forme (batch_size, memory_size, memory_width)
            beta: paramètre de netteté (batch_size, 1)
        Returns:
            weights: tenseur de forme (batch_size, memory_size)
        """
        # Normalisation pour la similarité cosinus
        key_norm = F.normalize(key, p=2, dim=-1).unsqueeze(1)
        memory_norm = F.normalize(memory, p=2, dim=-1)

        # Similarité cosinus
        cos_sim = torch.sum(key_norm * memory_norm, dim=-1)

        # Application de la netteté et softmax
        weights = F.softmax(cos_sim * beta, dim=-1)
        return weights

    def location_addressing(self, prev_weights, shift, gamma):
        """
        Adressage par location : rotation circulaire + sharpening.

        Args:
            prev_weights: (batch_size, memory_size)
            shift: poids de décalage (batch_size, 2*shift_range+1)
            gamma: paramètre de sharpening (batch_size, 1)
        Returns:
            weights: (batch_size, memory_size)
        """
        batch_size, memory_size = prev_weights.shape

        # Convolution circulaire (shift)
        shifts = torch.arange(-self.shift_range, self.shift_range + 1, device=prev_weights.device)
        shifted = torch.zeros_like(prev_weights)

        for s_idx, s in enumerate(shifts):
            rolled = torch.roll(prev_weights, shifts=int(s), dims=-1)
            shifted += shift[:, s_idx].unsqueeze(1) * rolled

        # Renormalisation
        shifted = shifted / (shifted.sum(dim=-1, keepdim=True) + 1e-8)

        # Sharpening
        sharpened = shifted ** gamma
        weights = sharpened / (sharpened.sum(dim=-1, keepdim=True) + 1e-8)
        return weights

    def forward(self, key, memory, beta, gate, shift, gamma, prev_weights):
        """
        Flux complet d'attention : content -> interpolation -> location -> sharpening.
        """
        # Adressage par contenu
        w_content = self.content_addressing(key, memory, beta)

        # Interpolation entre contenu et position précédente
        w_gated = gate * w_content + (1 - gate) * prev_weights

        # Adressage par location
        w_shifted = self.location_addressing(w_gated, shift, gamma)

        return w_shifted


class NTM(nn.Module):
    """
    Neural Turing Machine simplifiée avec contrôleur LSTM.

    Architecture :
        - Contrôleur : LSTM
        - Mémoire : matrice N × W entièrement différentiable
        - 1 tête de lecture + 1 tête d'écriture
        - Adressage hybride (contenu + location)
    """
    def __init__(self, input_size, output_size, memory_size=128, memory_width=20,
                 controller_size=100, shift_range=1):
        super().__init__()

        self.input_size = input_size
        self.output_size = output_size
        self.memory_size = memory_size
        self.memory_width = memory_width
        self.controller_size = controller_size
        self.shift_range = shift_range

        # Mémoire initialisée à zéro
        self.register_buffer('init_memory', torch.zeros(memory_size, memory_width))

        # Contrôleur LSTM
        self.controller = nn.LSTMCell(
            input_size=input_size + memory_width,
            hidden_size=controller_size
        )

        self._build_read_write_heads()

        self.attention = SoftAttention(memory_width, shift_range)

        self.output_layer = nn.Linear(controller_size, output_size)

        self._init_parameters()

    def _build_read_write_heads(self):
        """Construit les couches de lecture et d'écriture."""
        self.read_key_layer = nn.Linear(self.controller_size, self.memory_width)
        self.read_beta_layer = nn.Linear(self.controller_size, 1)
        self.write_key_layer = nn.Linear(self.controller_size, self.memory_width)
        self.write_beta_layer = nn.Linear(self.controller_size, 1)
        self.write_gate_layer = nn.Linear(self.controller_size, 1)
        self.write_shift_layer = nn.Linear(self.controller_size, 2 * self.shift_range + 1)
        self.write_gamma_layer = nn.Linear(self.controller_size, 1)
        self.write_erase_layer = nn.Linear(self.controller_size, self.memory_width)
        self.write_add_layer = nn.Linear(self.controller_size, self.memory_width)
        self.read_gate_layer = nn.Linear(self.controller_size, 1)
        self.read_shift_layer = nn.Linear(self.controller_size, 2 * self.shift_range + 1)
        self.read_gamma_layer = nn.Linear(self.controller_size, 1)

    def _init_parameters(self):
        """Initialisation des poids — cruciale pour la convergence des NTM."""
        for name, param in self.named_parameters():
            if 'weight' in name and param.dim() > 1:
                nn.init.xavier_uniform_(param)
            elif 'bias' in name:
                nn.init.zeros_(param)

        with torch.no_grad():
            self.write_shift_layer.bias.data.fill_(-10)
            self.read_shift_layer.bias.data.fill_(-10)
            self.write_erase_layer.bias.data.fill_(1.0)
            self.read_key_layer.bias.data.fill_(0.0)
            self.write_key_layer.bias.data.fill_(0.0)

    def init_state(self, batch_size, device):
        """Initialise la mémoire et les poids d'attention."""
        memory = self.init_memory.unsqueeze(0).repeat(batch_size, 1, 1).to(device)
        prev_read_weights = torch.ones(batch_size, self.memory_size, device=device) / self.memory_size
        prev_write_weights = torch.ones(batch_size, self.memory_size, device=device) / self.memory_size
        h = torch.zeros(batch_size, self.controller_size, device=device)
        c = torch.zeros(batch_size, self.controller_size, device=device)
        return memory, prev_read_weights, prev_write_weights, (h, c)

    def forward(self, inputs):
        """
        Propagation avant d'une séquence à travers la NTM.

        Args:
            inputs: (batch_size, seq_len, input_size)
        Returns:
            outputs: (batch_size, seq_len, output_size)
            memory_history: historique des états mémoire pour le débogage
        """
        batch_size, seq_len, _ = inputs.shape
        device = inputs.device

        memory, prev_read_w, prev_write_w, hc = self.init_state(batch_size, device)

        outputs = []
        memory_history = []

        for t in range(seq_len):
            x_t = inputs[:, t, :]

            # --- Lecture ---
            read_key = self.read_key_layer(hc[0])
            read_beta = F.softplus(self.read_beta_layer(hc[0])) + 1e-8
            read_gate = torch.sigmoid(self.read_gate_layer(hc[0]))
            read_shift = F.softmax(self.read_shift_layer(hc[0]), dim=-1)
            read_gamma = F.softplus(self.read_gamma_layer(hc[0])) + 1

            read_weights = self.attention(
                key=read_key, memory=memory, beta=read_beta,
                gate=read_gate.squeeze(-1), shift=read_shift,
                gamma=read_gamma, prev_weights=prev_read_w
            )

            read_vector = torch.sum(read_weights.unsqueeze(-1) * memory, dim=1)

            # --- Contrôleur ---
            controller_input = torch.cat([x_t, read_vector], dim=-1)
            h_new, c_new = self.controller(controller_input, hc)
            hc = (h_new, c_new)

            # --- Écriture ---
            write_key = self.write_key_layer(h_new)
            write_beta = F.softplus(self.write_beta_layer(h_new)) + 1e-8
            write_gate = torch.sigmoid(self.write_gate_layer(h_new))
            write_shift = F.softmax(self.write_shift_layer(h_new), dim=-1)
            write_gamma = F.softplus(self.write_gamma_layer(h_new)) + 1
            erase_vector = torch.sigmoid(self.write_erase_layer(h_new))
            add_vector = torch.tanh(self.write_add_layer(h_new))

            write_weights = self.attention(
                key=write_key, memory=memory, beta=write_beta,
                gate=write_gate.squeeze(-1), shift=write_shift,
                gamma=write_gamma, prev_weights=prev_write_w
            )

            # Application de l'écriture
            erase = 1 - write_weights.unsqueeze(-1) * erase_vector.unsqueeze(1)
            memory = memory * erase + write_weights.unsqueeze(-1) * add_vector.unsqueeze(1)

            # --- Sortie ---
            output = self.output_layer(h_new)
            outputs.append(output)

            prev_read_w = read_weights
            prev_write_w = write_weights
            memory_history.append(memory.detach().clone())

        outputs = torch.stack(outputs, dim=1)
        return outputs, memory_history

Tâche de Copie (Copy Task)

Le copy task est le test canonique des NTM : apprendre à mémoriser une séquence d’entrée puis à la reproduire exactement.

class CopyTask:
    """
    Tâche de copie : la NTM doit apprendre à reproduire une séquence.

    Format :
        [Séquence aléatoire] + [Délimiteur de fin] + [Délimiteur de début de rappel]
    La NTM doit produire la séquence originale après le délimiteur.
    """
    def __init__(self, seq_length, input_dim):
        self.seq_length = seq_length
        self.input_dim = input_dim

    def generate_batch(self, batch_size=32, device='cpu'):
        """Génère un batch de données d'entraînement."""
        sequence = torch.rand(batch_size, self.seq_length, self.input_dim, device=device)

        end_marker = torch.zeros(batch_size, 1, self.input_dim, device=device)
        end_marker[:, :, -1] = 1.0

        start_marker = torch.zeros(batch_size, 1, self.input_dim, device=device)
        start_marker[:, :, -2] = 1.0

        inputs = torch.cat([sequence, start_marker], dim=1)
        targets = torch.cat([sequence, end_marker], dim=1)

        return inputs, targets


def train_copy_task(ntm, num_iterations=10000, batch_size=32, seq_length=8, lr=1e-4):
    """Entraîne la NTM sur le copy task."""
    task = CopyTask(seq_length, ntm.input_size)
    optimizer = torch.optim.Adam(ntm.parameters(), lr=lr)
    criterion = nn.BCEWithLogitsLoss()

    for iteration in range(num_iterations):
        inputs, targets = task.generate_batch(batch_size)
        outputs, _ = ntm(inputs)

        loss = criterion(outputs, targets)
        optimizer.zero_grad()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(ntm.parameters(), max_norm=10.0)
        optimizer.step()

        if iteration % 500 == 0:
            print(f"Iteration {iteration} | Perte : {loss.item():.6f}")

    print(f"Entraînement terminé. Perte finale : {loss.item():.6f}")
    return ntm


def evaluate_copy(ntm, seq_length=12):
    """
    Évalue la capacité de copie sur une séquence de longueur non vue.
    C'est le test de généralisation clé des NTM.
    """
    ntm.eval()
    task = CopyTask(seq_length, ntm.input_size)
    inputs, targets = task.generate_batch(batch_size=1, device='cpu')

    with torch.no_grad():
        outputs, _ = ntm(inputs)
        predicted = (torch.sigmoid(outputs) > 0.5).float()

    accuracy = (predicted == targets).float().mean()
    print(f"Précision sur séquence de longueur {seq_length} : {accuracy.item():.4f}")
    return accuracy

Tâche d’Association (Association Task)

class AssociationTask:
    """
    Tâche d'association : la NTM doit apprendre à associer des paires
    input -> output puis généraliser à de nouvelles associations.

    Format :
        Phase d'encodage : (clé, valeur) présentées successivement
        Phase de rappel : on donne une clé, la NTM doit produire la valeur
    """
    def __init__(self, num_pairs, key_dim, value_dim):
        self.num_pairs = num_pairs
        self.key_dim = key_dim
        self.value_dim = value_dim

    def generate_batch(self, batch_size=32, device='cpu'):
        keys = torch.zeros(batch_size, self.num_pairs, self.key_dim, device=device)
        for b in range(batch_size):
            perm = torch.randperm(self.key_dim)[:self.num_pairs]
            for i, idx in enumerate(perm):
                keys[b, i, idx] = 1.0

        values = torch.rand(batch_size, self.num_pairs, self.value_dim, device=device)

        inputs = torch.cat([keys, keys], dim=1)
        targets = torch.cat([values, values], dim=1)

        return inputs, targets

Hyperparamètres

Les hyperparamètres d’une NTM sont nombreux et leur réglage est crucial pour la convergence :

Hyperparamètre Symbole Valeur typique Rôle
Taille mémoire N 16 – 256 Nombre d’emplacements mémoire. Plus N est grand, plus la NTM peut stocker d’informations, mais le coût computationnel croît linéairement.
Largeur mémoire W 10 – 100 Dimension de chaque vecteur mémoire. Détermine la richesse informationnelle de chaque emplacement.
Type de contrôleur LSTM / GRU / MLP Le LSTM est le choix classique. Les GRU sont plus légers. Les MLP sont plus simples mais moins performants sur des tâches séquentielles.
Taille du contrôleur 50 – 256 Dimension de l’état caché du contrôleur. Un contrôleur plus grand a plus de capacité de calcul mais risque de surapprendre.
Nombre de lecteurs 1 – 4 Chaque tête de lecture peut extraire un vecteur différent de la mémoire au même pas de temps.
Nombre de rédacteurs 1 – 4 Chaque tête d’écriture modifie la mémoire simultanément. Trop de rédacteurs peuvent créer des interférences.
Plage de décalage 1 – 3 Portée du shift circulaire. Une plage de 1 permet de se déplacer à l’emplacement adjacent.
Taux d’apprentissage 1e-4 – 1e-3 Adam avec gradient clipping (norme max ≈ 10) est quasi universel pour les NTM.

Recommandations pratiques

  • Pour le copy task : N=128, W=20, contrôleur LSTM de taille 100, 1 lecteur, 1 rédacteur suffisent pour des séquences de longueur 10-20.
  • Pour l’association : N=256, W=30, contrôleur de taille 200 sont recommandés car la tâche nécessite plus de capacité de stockage distinct.
  • Initialisation : L’initialisation des poids de shift à -10 (favorisant le déplacement 0) et des vecteurs d’effacement à 1.0 (pas d’effacement par défaut) sont des pratiques éprouvées qui accélèrent considérablement la convergence.
  • Gradient clipping : Indispensable. Sans clipping à une norme de 10, les NTM divergent presque systématiquement à cause des exponentielles dans le softmax d’attention.

Avantages et Limites

Avantages

  1. Capacité de mémorisation explicite : Contrairement aux LSTM dont la mémoire est implicite dans les connexions récurrentes, la NTM possède un espace de stockage dédié et consultable. Cela permet de retenir exactement l’information nécessaire, pas seulement des résumés compressés.
  2. Généralisation à des longueurs non vues : C’est l’avantage le plus remarquable. Une NTM entraînée sur des séquences de longueur 8 peut souvent copier des séquences de longueur 20 ou plus — ce qu’un LSTM classique échoue à faire. La séparation computation/mémoire permet cette extrapolation.
  3. Apprentissage algorithmique : Les NTM peuvent apprendre des pseudo-algorithmes : tri, recherche, copie répétée. Elles développent des comportements émergents ressemblant à des pointeurs et des boucles, sans qu’on les leur ait programmées.
  4. Totalement différentiable : Toutes les opérations — lecture, écriture, attention — sont lisses et dérivables. L’entraînement par rétropropagation fonctionne end-to-end, sans besoin de techniques de reinforcement learning ou de politiques stochastiques.

Limites

  1. Complexité computationnelle élevée : Chaque pas de temps nécessite de calculer la similarité cosinus entre le key vector et tous les N emplacements mémoire. La complexité est O(N × W) par tête, par pas de temps. Avec N=256, c’est 200 fois plus coûteux qu’un LSTM de taille équivalente.
  2. Difficulté d’entraînement : Les NTM convergent lentement et nécessitent un réglage minutieux des hyperparamètres. Le paysage de perte est très irrégulier, avec de nombreux minima locaux. L’initialisation est critique.
  3. Mémoire de taille fixe : Contrairement à la pile d’un ordinateur qui peut s’étendre, la mémoire de la NTM a une taille N prédéfinie. Si la tâche nécessite plus d’emplacements, la NTM échoue. C’est le problème que le DNC résout partiellement avec l’allocation dynamique.
  4. Échelle limitée : Les NTM fonctionnent bien sur des tâches synthétiques courtes mais ne passent pas à l’échelle des tâches du monde réel (traitement de langage naturel, vision par ordinateur). C’est pourquoi le champ a évolué vers les Transformers et les mécanismes d’attention externe à grande échelle.
  5. Interprétabilité difficile : Bien que la mémoire soit explicite, comprendre ce qui est stocké à chaque emplacement et pourquoi reste difficile. Les poids d’attention sont denses et leur interprétation n’est pas triviale.

4 Cas d’Usage Concrets

1. Copie et Récurrence de Séquences Longues

Dans les systèmes de dialogue ou de génération de texte, une NTM peut servir de mémoire de contexte à long terme. Quand une conversation dépasse la fenêtre du contexte immédiat, la NTM stocke les éléments importants dans sa mémoire externe et les récupère quand nécessaire — par exemple, le nom d’un utilisateur mentionné il y a 200 tours de parole.

2. Raisonnement sur des Graphes

Les NTM peuvent apprendre à traverser des graphes en utilisant leur mémoire comme espace de travail. Chaque nœud visité peut être stocké dans un emplacement mémoire, et les têtes de lecture/écriture servent à suivre le chemin parcouru. Des recherches ont montré que les NTM peuvent apprendre des algorithmes de parcours de graphe comme BFS et DFS de manière purement apprise.

3. Contrôle Robotique avec Mémoire

Un robot mobile peut utiliser une NTM comme carte cognitive : la mémoire externe stocke les positions explorées et leurs propriétés, tandis que le contrôleur décide de la prochaine action. Contrairement à une grille d’occupation classique, la carte apprise par la NTM est sémantique — elle encode non seulement “il y a un mur ici” mais “cette zone a été explorée et contient un objet intéressant”.

4. Programmation Neuronale

La NTM est le fondement de la programmation neuronale : apprendre des programmes à partir d’exemples. En combinant la mémoire externe avec un contrôleur suffisamment expressif, on peut apprendre à exécuter des programmes simples (addition, tri, recherche binaire) directement à partir de paires input/output. Cette approche ouvre la voie à des systèmes qui apprennent non pas une fonction fixe, mais un algorithme généralisable.

Voir Aussi

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.