PyTorch torchtext

Bien que l'écosystème PyTorch proposetorchvisionle traitement des données d'images,torchaudiole traitement des données audio, mais dans le domaine du traitement du texte, celle officiellement fournietorchtextLa bibliothèque a subi quelques changements. Cette section présente comment effectuer le prétraitement des données textuelles, la construction du vocabulaire, le chargement des données et d'autres opérations à l'aide de diverses méthodes.

Remarque : La bibliothèque torchtext a subi quelques refactorisations. Il est recommandé d'utilisertorchtext.legacyou de construire votre propre pipeline de traitement de texte. La dernière version de torchtext est revenue et fournit une API plus moderne.


Notions de base du prétraitement des données textuelles

Le prétraitement de texte est la première étape des tâches de NLP, incluant la tokenisation, la construction de vocabulaire, l'encodage et d'autres opérations.

1.1 Pipeline de base de traitement de texte

Exemple

import re
from collections import Counter

class SimpleTokenizer:
    """
Tokeniseur simple : tokeniser en fonction des espaces et de la ponctuation
    """

    def __init__(self):
        # Mappage de ponctuation
        self.punctuation = str.maketrans('', '', '.,!?;:"\'-()[]{}')

    def tokenize(self, text):
        # Convertir en minuscules
        text = text.lower()
        # Supprimer la ponctuation
        text = text.translate(self.punctuation)
        # Tokeniser
        tokens = text.split()
        return tokens


class Vocabulary:
    """
Construction du vocabulaire
    """

    def __init__(self, min_freq=2, max_size=10000):
        self.min_freq = min_freq
        self.max_size = max_size
        self.word2idx = {'<PAD>': 0, '<UNK>': 1}
        self.idx2word = {0: '<PAD>', 1: '<UNK>'}
        self.word_count = Counter()

    def build_vocab(self, texts):
        """Construire le vocabulaire à partir d'une liste de textes"""
        tokenizer = SimpleTokenizer()

        # Compter les fréquences des mots
        for text in texts:
            tokens = tokenizer.tokenize(text)
            self.word_count.update(tokens)

        # Construire le vocabulaire
        for word, count in self.word_count.most_common(self.max_size):
            if count < self.min_freq:
                break
            if word not in self.word2idx:
                idx = len(self.word2idx)
                self.word2idx[word] = idx
                self.idx2word[idx] = word

        print(f"Taille du vocabulaire : {len(self.word2idx)}")

    def encode(self, text, max_len=50):
        """Encoder le texte comme une séquence d'indices"""
        tokenizer = SimpleTokenizer()
        tokens = tokenizer.tokenize(text)[:max_len]

        # Encodage
        indices = [
            self.word2idx.get(token, self.word2idx['<UNK>'])
            for token in tokens
        ]

        # Remplir avec des zéros
        if len(indices) < max_len:
            indices += [self.word2idx['<PAD>']] * (max_len - len(indices))

        return indices

    def decode(self, indices):
        """Décode une séquence d'indices en texte"""
        tokens = [self.idx2word.get(idx, '<UNK>') for idx in indices]
        return ' '.join(tokens)


# Exemple d'utilisation
textes = [
    "Bonjour le monde",
    "Ceci est un test",
    "PyTorch est excellent pour l'apprentissage profond",
    "Le traitement du langage naturel est amusant",
    "L'apprentissage profond permet de nombreuses applications",
]

vocab = Vocabulary(min_freq=1, max_size=100)
vocab.build_vocab(texts)

# Encodage
encoded = vocab.encode("Bonjour le monde de l'apprentissage profond !", max_len=10)
print(f"Résultat encodé : {encoded}")

# Décodage
decoded = vocab.decode(encoded)
print(f"Résultat décodé : {decoded}")

2. Utilisation de torchtext (Legacy)

Si torchtext est installé, vous pouvez utiliser le module legacy pour le traitement de texte.

2.1 Installation et import

Exemple

# Installer torchtext
# pip install torchtext

# Importer le module legacy
try:
    import torchtext
    from torchtext.legacy import data
    from torchtext.legacy import datasets
    print(f"Version de torchtext : {torchtext.__version__}")
    TORCHTEXT_AVAILABLE = True
except ImportError:
    print("torchtext n'est pas installé, utilisation d'une implémentation personnalisée")
    TORCHTEXT_AVAILABLE = False

# Ou essayez la nouvelle version
try:
    from torchtext import transforms
    from torchtext.datasets import AG_NEWS
    print("La nouvelle version de torchtext est disponible")
except ImportError:
    print("La nouvelle version de torchtext n'est pas disponible")

2.2 Field et Dataset

Exemple

# Utiliser torchtext.legacy
from torchtext.legacy import data
from torchtext.legacy import datasets
from torchtext.legacy.data import Field, TabularDataset, BucketIterator

# Définir les champs
TEXT = Field(
    tokenize='spacy',           # Utiliser spacy pour la tokenisation
    tokenizer_language='en_core_web_sm',
    lower=True,                 # Convertir en minuscules
    include_lengths=True,       # Retourner la longueur de la séquence
    batch_first=True            # Dimension batch en premier
)

LABEL = Field(
    sequential=False,
    use_vocab=False,
    dtype=torch.long
)

# Définir le jeu de données
# Supposer un format de fichier CSV : label,text
# 1,Ceci est un avis positif
# 0,Ceci est un avis négatif

# Ou utilisez un jeu de données intégré (par ex., IMDB)
# train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)

print("Configuration de Field et Dataset terminée")

2.3 Construction du vocabulaire et des itérateurs

Exemple

# Construire le vocabulaire
# TEXT.build_vocab(train_data, vectors="glove.6B.100d", max_size=10000)

# Créer un itérateur
# train_iterator, test_iterator = BucketIterator.splits(
#     (train_data, test_data),
#     batch_size=32,
#     sort_within_batch=True,
#     device=torch.device('cuda')
# )

# Itérer l'entraînement
# for batch in train_iterator:
#     text, lengths = batch.text
#     labels = batch.label
# # Code d'entraînement

print("Configuration du vocabulaire et de l'itérateur terminée")

3. Pipeline de données NLP personnalisé

Il est recommandé d'utiliser une approche personnalisée plus flexible de traitement des données qui ne dépend pas de torchtext.

3.1 Implémentation de la classe Dataset

Exemple

import torch
from torch.utils.data import Dataset, DataLoader
from collections import Counter
import re

class TextDataset(Dataset):
    """
Jeu de données textuelles
    """

    def __init__(self, texts, labels, vocab=None, max_len=128, min_freq=2):
        self.texts = texts
        self.labels = labels
        self.max_len = max_len

        # Construire ou utiliser un vocabulaire existant
        if vocab is None:
            self.vocab = self._build_vocab(texts, min_freq)
        else:
            self.vocab = vocab

    def _build_vocab(self, texts, min_freq):
        """Construire le vocabulaire"""
        word_counts = Counter()

        for text in texts:
            tokens = self._tokenize(text)
            word_counts.update(tokens)

        # Créer le vocabulaire
        word2idx = {'<PAD>': 0, '<UNK>': 1}
        for word, count in word_counts.items():
            if count >= min_freq:
                word2idx[word] = len(word2idx)

        return word2idx

    def _tokenize(self, text):
        """Tokenisation simple"""
        # Convertir en minuscules
        text = text.lower()
        # Supprimer les caractères spéciaux, conserver les caractères alphanumériques et les espaces
        text = re.sub(r'[^a-z0-9\s]', ' ', text)
        # Tokeniser
        tokens = text.split()
        return tokens

    def _encode(self, text):
        """Encoder le texte"""
        tokens = self._tokenize(text)[:self.max_len]
        indices = [
            self.vocab.get(token, self.vocab['<UNK>'])
            for token in tokens
        ]

        # Remplir avec des zéros
        if len(indices) < self.max_len:
            indices += [self.vocab['<PAD>']] * (self.max_len - len(indices))

        return indices

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, idx):
        text = self.texts[idx]
        label = self.labels[idx]

        encoded = self._encode(text)
        return torch.tensor(encoded, dtype=torch.long), torch.tensor(label, dtype=torch.long)


# Exemple d'utilisation
textes = [
    "C'est un excellent film",
    "J'ai détesté ce film",
    "Interprétation incroyable",
    "Jeu d'acteur terrible",
    "Je recommande vivement",
]

labels = [1, 0, 1, 0, 1]

dataset = TextDataset(texts, labels, max_len=10)
print(f"Taille du jeu de données: {len(dataset)}")
print(f"Taille du vocabulaire: {len(dataset.vocab)}")

# Obtenir un échantillon
text, label = dataset[0]
print(f"Encodage du texte : {text[:5]}...")
print(f"Étiquette : {label}")

3.2 Tokeniseurs avancés

Exemple

# Utiliser spacy pour la tokenisation avancée
def tokenize_with_spacy(text):
    """Tokeniser avec spacy"""
    try:
        import spacy
        nlp = spacy.load("en_core_web_sm")
        doc = nlp(text)
        return [token.text for token in doc]
    except ImportError:
        print("spacy n'est pas installé, utilisation d'une tokenisation simple")
        return text.lower().split()


# Utiliser nltk pour la tokenisation et le stemming
def tokenize_with_nltk(text):
    """Tokeniser avec nltk"""
    try:
        import nltk
        from nltk.tokenize import word_tokenize
        from nltk.stem import PorterStemmer

        # Tokeniser
        tokens = word_tokenize(text.lower())

        # Facultatif : racinisation
        stemmer = PorterStemmer()
        tokens = [stemmer.stem(token) for token in tokens if token.isalnum()]

        return tokens
    except ImportError:
        return text.lower().split()


# Utiliser SentencePiece pour la tokenisation en sous-mots
class SentencePieceTokenizer:
    """
Utiliser SentencePiece pour la tokenisation en sous-mots
    """

    def __init__(self, model_path=None):
        self.model_path = model_path
        self.sp = None

    def train(self, texts, vocab_size=10000):
        """Entraîner le modèle SentencePiece"""
        try:
            import sentencepiece as spm
            import tempfile

            # Écrire dans un fichier temporaire
            with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as f:
                for text in texts:
                    f.write(text + '\n')
                temp_file = f.name

            # Entraîner
            spm.SentencePieceTrainer.train(
                input=temp_file,
                model_prefix='spm_model',
                vocab_size=vocab_size,
                character_coverage=1.0,
                model_type='unigram',
            )

            self.sp = spm.SentencePieceProcessor()
            self.sp.load('spm_model.model')

        except ImportError:
            print("sentencepiece n'est pas installé")

    def encode(self, text):
        if self.sp:
            return self.sp.encode(text, out_type=str)
        return text.split()

    def decode(self, ids):
        if self.sp:
            return self.sp.decode(ids)
        return ' '.join(ids)

3.3 Chargeur de données complet

Exemple

import torch
from torch.utils.data import Dataset, DataLoader
from collections import Counter

class NLPDataset(Dataset):
    """
Classe complète de jeu de données NLP
Prend en charge les séquences de longueur variable, la construction du vocabulaire et le remplissage par lots
    """

    def __init__(self, texts, labels, min_freq=2, max_vocab=30000):
        self.texts = texts
        self.labels = labels
        self.min_freq = min_freq

        # Construire le vocabulaire
        self.word2idx, self.idx2word = self._build_vocab(texts, max_vocab)
        self.pad_idx = self.word2idx['<PAD>']
        self.unk_idx = self.word2idx['<UNK>']

    def _tokenize(self, text):
        text = text.lower()
        text = re.sub(r'[^a-z0-9\s]', ' ', text)
        return text.split()

    def _build_vocab(self, texts, max_vocab):
        """Construire le vocabulaire"""
        counter = Counter()
        for text in texts:
            tokens = self._tokenize(text)
            counter.update(tokens)

        # Construire le vocabulaire
        word2idx = {'<PAD>': 0, '<UNK>': 1}
        idx2word = {0: '<PAD>', 1: '<UNK>'}

        for word, count in counter.most_common(max_vocab):
            if count >= self.min_freq and word not in word2idx:
                idx = len(word2idx)
                word2idx[word] = idx
                idx2word[idx] = word

        return word2idx, idx2word

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, idx):
        text = self.texts[idx]
        tokens = self._tokenize(text)
        indices = [self.word2idx.get(t, self.unk_idx) for t in tokens]

        return {
            'input': indices,
            'label': self.labels[idx],
            'length': len(indices)
        }


def collate_fn(batch, pad_idx=0):
    """
Fonction de collate personnalisée : gérer les séquences de longueur variable
    """

    # Trier par longueur par ordre décroissant
    batch.sort(key=lambda x: x['length'], reverse=True)

    texts = [item['input'] for item in batch]
    labels = [item['label'] for item in batch]
    lengths = [item['length'] for item in batch]

    # Compléter à la même longueur
    max_len = max(lengths)
    padded = [text + [pad_idx] * (max_len - len(text)) for text in texts]

    return {
        'input': torch.tensor(padded, dtype=torch.long),
        'labels': torch.tensor(labels, dtype=torch.long),
        'lengths': torch.tensor(lengths, dtype=torch.long)
    }


# Utiliser DataLoader
def create_dataloader(texts, labels, batch_size=32, shuffle=True):
    """Créer un chargeur de données"""
    dataset = NLPDataset(texts, labels)
    pad_idx = dataset.pad_idx

    dataloader = DataLoader(
        dataset,
        batch_size=batch_size,
        shuffle=shuffle,
        collate_fn=lambda b: collate_fn(b, pad_idx)
    )

    return dataloader, dataset


# Simuler des données
textes = [
    "J'adore ce film",
    "C'est un mauvais film",
    "Excellent film",
    "Jeu d'acteur terrible",
    "Je recommande ceci",
    "Pas la peine de le regarder",
]

labels = [1, 0, 1, 0, 1, 0]

dataloader, dataset = create_dataloader(texts, labels, batch_size=2)

for batch in dataloader:
    print("Forme de l'entrée :", batch['input'].shape)
    print("Étiquettes :", batch['labels'])
    print("Longueurs :", batch['lengths'])
    print("---")

4. Chargement des vecteurs de mots pré-entraînés

L'utilisation de vecteurs de mots pré-entraînés peut améliorer les performances du modèle.

4.1 Vecteurs de mots GloVe

Exemple

import torch
import numpy as np

def load_glove_vectors(filepath, word2idx, embedding_dim=300):
    """
Charger les vecteurs de mots pré-entraînés GloVe

Paramètres :
filepath : chemin du fichier GloVe
word2idx: dictionnaire de vocabulaire
embedding_dim: dimension des vecteurs de mots
    """

    print("Chargement des vecteurs de mots GloVe...")

    # Initialiser la matrice d'embedding
    num_words = len(word2idx)
    embeddings = np.random.randn(num_words, embedding_dim).astype(np.float32)
    embeddings[word2idx['<PAD>']] = np.zeros(embedding_dim)  # Mettre le vecteur PAD à zéro

    words_loaded = 0

    with open(filepath, 'r', encoding='utf-8') as f:
        for line in f:
            values = line.strip().split()
            word = values[0]

            if word in word2idx:
                idx = word2idx[word]
                vector = np.asarray(values[1:], dtype=np.float32)
                if len(vector) == embedding_dim:
                    embeddings[idx] = vector
                    words_loaded += 1

    print(f"Vecteurs de mots chargés : {words_loaded}/{num_words}")

    return torch.from_numpy(embeddings)


# Chargement simulé
def create_pretrained_embedding(word2idx, embedding_dim=300, pretrained_path=Aucune):
    """
Créer une couche de plongement pré-entraînée
    """

    if pretrained_path and False:  # Définir sur True et fournir un chemin valide
        weights = load_glove_vectors(pretrained_path, word2idx, embedding_dim)
    else:
        # Utiliser une initialisation aléatoire
        num_words = len(word2idx)
        weights = torch.randn(num_words, embedding_dim) * 0.1

    embedding = torch.nn.Embedding.from_pretrained(weights, padding_idx=0)
    return embedding


# Exemple
word2idx = {'<PAD>': 0, '<UNK>': 1, 'hello': 2, 'world': 3, 'test': 4}
embedding = create_pretrained_embedding(word2idx, embedding_dim=100)

print(f"Forme de la couche d'embedding : {embedding.weight.shape}")

4.2 Chargement de Word2Vec avec gensim

Exemple

def load_word2vec(word2idx, model_path=None):
    """
Chargement de Word2Vec avec gensim
    """

    try:
        from gensim.models import KeyedVectors

        # Charger le modèle
        # model = KeyedVectors.load_word2vec_format(model_path, binary=True)

        # Créer la matrice de plongement
        embedding_dim = 300
        num_words = len(word2idx)
        embeddings = np.random.randn(num_words, embedding_dim).astype(np.float32)

        # Remplir les vecteurs de mots
        embeddings[word2idx['<PAD>']] = np.zeros(embedding_dim)

        # Charger les vecteurs de mots
        # for word, idx in word2idx.items():
        # if word in model:
        # embeddings[idx] = model[word]

        return torch.from_numpy(embeddings)

    except ImportError:
        print("gensim n'est pas installé")
        return None

4.3 Embeddings pré-entraînés personnalisés

Exemple

import torch
import torch.nn as nn

class PretrainedEmbedding(nn.Module):
    """
Couche Embedding qui prend en charge le chargement de vecteurs de mots pré-entraînés
    """

    def __init__(self, vocab_size, embed_dim, pretrained_weights=Aucune,
                 padding_idx=0, freeze=False):
        super().__init__()

        self.embedding = nn.Embedding(
            vocab_size,
            embed_dim,
            padding_idx=padding_idx
        )

        # Charger les poids pré-entraînés
        if pretrained_weights is not None:
            self.embedding.weight.data.copy_(pretrained_weights)

        # Indique s'il faut geler
        if freeze:
            self.embedding.weight.requires_grad = False

    def forward(self, x):
        return self.embedding(x)


# Exemple d'utilisation
vocab_size = 10000
embed_dim = 300
pretrained = torch.randn(vocab_size, embed_dim) * 0.1

embedding_layer = PretrainedEmbedding(
    vocab_size,
    embed_dim,
    pretrained_weights=pretrained,
    padding_idx=0,
    freeze=False  # Définir sur True pour geler la couche d'embedding
)

# Test
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
output = embedding_layer(x)
print(f"Forme de l'entrée : {x.shape}")
print(f"Forme de sortie : {output.shape}")

5. Augmentation des données textuelles

L'augmentation des données peut améliorer la capacité de généralisation du modèle.

5.1 Augmentation par rétro-traduction

Exemple

# L'augmentation par rétro-traduction nécessite une API de traduction ; ce qui suit est un exemple conceptuel

def back_translation_augment(text, translator):
    """
Augmentation par rétro-traduction : traduire le texte dans une autre langue, puis le traduire à nouveau
    """

    # Traduire vers la langue cible
    translated = translator.translate(text, dest='fr')
    # Traduire à nouveau vers la langue source
    back_translated = translator.translate(translated.text, dest='en')
    return back_translated.text

# Exemple d'utilisation
# from googletrans import Translator
# translator = Translator()
# augmented_text = back_translation_augment("I love this movie", translator)

5.2 Remplacement de synonymes

Exemple

import random

def synonym_replacement(text, n=1, stop_words=None):
    """
Remplacement par synonymes
    """

    if stop_words is None:
        stop_words = {'a', 'un', 'le', 'est', 'sont', 'était', 'étaient'}

    words = text.lower().split()
    replaceable = [i for i, w in enumerate(words) if w not in stop_words]

    if not replaceable:
        return text

    n = min(n, len(replaceable))
    replace_idx = random.sample(replaceable, n)

    # Mappage simplifié des synonymes (devrait en fait utiliser WordNet)
    synonym_map = {
        'bon': ['génial', 'excellent', 'agréable'],
        'mauvais': ['médiocre', 'terrible', 'affreux'],
        'film': ['film', 'cinéma'],
        'aimé': ['adoré', 'apprécié'],
    }

    for idx in replace_idx:
        word = words[idx]
        if word in synonym_map:
            words[idx] = random.choice(synonym_map[word])

    return ' '.join(words)


# Exemple d'utilisation
text = "J'ai aimé ce bon film"
augmented = synonym_replacement(text, n=2)
print(f"Phrase originale : {text}")
print(f"Augmenté : {augmented}")

5.3 Insertion et suppression aléatoires

Exemple

import random

def random_insertion(text, n=1):
    """
Insertion aléatoire : insérer aléatoirement des mots dans le texte
    """

    words = text.lower().split()
    for _ in range(n):
        if len(words) > 1:
            idx = random.randint(0, len(words) - 1)
            # Mots insérés simplifiés
            insert_words = ['really', 'very', 'quite', 'actually']
            words.insert(idx, random.choice(insert_words))
    return ' '.join(words)


def random_deletion(text, p=0.1):
    """
Suppression aléatoire : supprimer des mots avec une probabilité p
    """

    words = text.lower().split()
    if len(words) == 1:
        return text

    remaining = [w for w in words if random.random() > p]
    if len(remaining) == 0:
        return random.choice(words)

    return ' '.join(remaining)


def random_swap(text, n=1):
    """
Échange aléatoire : échanger aléatoirement les positions de deux mots
    """

    words = text.lower().split()
    if len(words) < 2:
        return text

    for _ in range(n):
        idx1, idx2 = random.sample(range(len(words)), 2)
        words[idx1], words[idx2] = words[idx2], words[idx1]

    return ' '.join(words)


# Exemple d'utilisation
text = "C'est un excellent film sur l'amour et le bonheur"

print("Original :", text)
print("Inséré :", random_insertion(text, n=2))
print("Supprimé :", random_deletion(text, p=0.2))
print("Échangé :", random_swap(text, n=2))

6. Exemples de tâches NLP courantes

6.1 Pipeline complet de classification de texte

Exemple

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

# 1. Préparation des données
textes = [
    "J'adore ce produit, il est incroyable !",
    "Qualité terrible, gaspillage d'argent.",
    "Très bon rapport qualité-prix.",
    "Pas satisfait de l'achat.",
    "Le meilleur achat que j'aie jamais fait !",
    "Très déçu de cet article.",
]

labels = [1, 0, 1, 0, 1, 0]  # 1 : positif, 0 : négatif

# 2. Jeu de données
class TextClassificationDataset(Dataset):
    def __init__(self, texts, labels, max_len=50):
        self.texts = texts
        self.labels = labels
        self.max_len = max_len
        self.vocab = self._build_vocab(texts)

    def _build_vocab(self, texts):
        vocab = {'<PAD>': 0, '<UNK>': 1}
        for text in texts:
            for word in text.lower().split():
                if word not in vocab:
                    vocab[word] = len(vocab)
        return vocab

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, idx):
        text = self.texts[idx]
        label = self.labels[idx]

        # Encodage simple
        tokens = text.lower().split()[:self.max_len]
        indices = [self.vocab.get(t, 1) for t in tokens]

        # Remplissage
        if len(indices) < self.max_len:
            indices += [0] * (self.max_len - len(indices))

        return torch.tensor(indices, dtype=torch.long), torch.tensor(label, dtype=torch.long)

# 3. Modèle
class TextClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim=128, hidden_dim=64, num_classes=2):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)

    def forward(self, x):
        embedded = self.embedding(x)
        _, (hidden, _) = self.lstm(embedded)
        output = self.fc(hidden.squeeze(0))
        return output

# 4. Entraînement
dataset = TextClassificationDataset(texts, labels)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)

model = TextClassifier(vocab_size=len(dataset.vocab))
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# Entraîner pendant quelques époques
model.train()
for epoch in range(10):
    total_loss = 0
    for texts_batch, labels_batch in dataloader:
        optimizer.zero_grad()
        outputs = model(texts_batch)
        loss = criterion(outputs, labels_batch)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()

    print(f"Époque {epoch+1}, Perte : {total_loss/len(dataloader):.4f}")

print("Entraînement terminé !")

6.2 Exemple d'étiquetage de séquence (NER)

Exemple

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

# Jeu de données d'étiquetage de séquence
class NERDataset(Dataset):
    """
Jeu de données de reconnaissance d'entités nommées
Format : [(word, tag), ...]
    """

    def __init__(self, sentences_tags, word2idx, tag2idx, max_len=50):
        self.sentences_tags = sentences_tags
        self.word2idx = word2idx
        self.tag2idx = tag2idx
        self.max_len = max_len

    def __len__(self):
        return len(self.sentences_tags)

    def __getitem__(self, idx):
        sentence_tags = self.sentences_tags[idx]
        words = [wt[0] for wt in sentence_tags]
        tags = [wt[1] for wt in sentence_tags]

        # Encodage
        word_ids = [self.word2idx.get(w.lower(), 1) for w in words[:self.max_len]]
        tag_ids = [self.tag2idx[t] for t in tags[:self.max_len]]

        # Remplissage
        if len(word_ids) < self.max_len:
            word_ids += [0] * (self.max_len - len(word_ids))
            tag_ids += [0] * (self.max_len - len(tag_ids))

        return {
            'words': torch.tensor(word_ids, dtype=torch.long),
            'tags': torch.tensor(tag_ids, dtype=torch.long)
        }

# Modèle NER
class NERModel(nn.Module):
    def __init__(self, vocab_size, tag_size, embed_dim=128, hidden_dim=256):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True, bidirectional=True)
        self.fc = nn.Linear(hidden_dim * 2, tag_size)

    def forward(self, x):
        embedded = self.embedding(x)
        lstm_out, _ = self.lstm(embedded)
        logits = self.fc(lstm_out)
        return logits


# Exemple de données
data = [
    [("Jean", "B-PER"), ("vit", "O"), ("à", "O"), ("New", "B-LOC"), ("York", "I-LOC"), (".", "O")],
    [("Apple", "B-ORG"), ("est", "O"), ("a", "O"), ("entreprise", "O"), (".", "O")],
]

# Construire le vocabulaire des mots et la table des tags
word2idx = {'<PAD>': 0, '<UNK>': 1}
tag2idx = {'O': 0, 'B-PER': 1, 'I-PER': 2, 'B-LOC': 3, 'I-LOC': 4, 'B-ORG': 5, 'I-ORG': 6}

for sent in data:
    for word, tag in sent:
        if word.lower() not in word2idx:
            word2idx[word.lower()] = len(word2idx)

print(f"Taille du vocabulaire : {len(word2idx)}")
print(f"Nombre d'étiquettes : {len(tag2idx)}")

7. Alternatives recommandées

7.1 Autres bibliothèques de traitement du texte

Nom de la bibliothèque Fonctionnalités Scénarios applicables
HuggingFace Datasets Chargement et traitement des données Tâches générales de NLP
spacy Outils NLP avancés Tokenisation, NER, analyse des dépendances
NLTK Outils NLP classiques Enseignement, prototypage
textblob Simple et facile à utiliser Traitement de texte rapide

7.2 Utilisation de HuggingFace Datasets

Exemple

# Utiliser la bibliothèque HuggingFace Datasets
# pip install datasets

from datasets import load_dataset

# Charger le jeu de données
# dataset = load_dataset("imdb")
# dataset = load_dataset("squad")

# Prétraitement des données
# def preprocess_function(examples):
#     return tokenizer(examples['text'], truncation=True, padding='max_length')

# tokenized_dataset = dataset.map(preprocess_function, batched=True)

print("Exemple d'utilisation de HuggingFace Datasets :")
print("from datasets import load_dataset")
print("dataset = load_dataset('imdb')")

8. Référence rapide de l’API

8.1 Opérations courantes de traitement de texte

Opération Méthode
Tokenisation text.split(), spacy, nltk, jieba
Construction du vocabulaire Counter, vocab.build_vocab()
Encodage vocab.encode(), tokenizer.encode()
Décodage vocab.decode(), tokenizer.decode()
Remplissage pad_sequence, collate_fn
Chargement des vecteurs de mots Chargement direct avec Gensim, GloVe

8.2 Méthodes d'augmentation de données

Méthode Description
Remplacement par synonymes Remplacer aléatoirement des mots par des synonymes
Insertion aléatoire Insérer aléatoirement des mots
Suppression aléatoire Supprimer aléatoirement des mots
Échange aléatoire Échanger aléatoirement les positions des mots
Rétrotraduction Traduire puis retraduire

8.3 Pipeline de traitement des données recommandé

1. 数据清洗
   - 去除 HTML 标签、特殊字符
   - 统一编码、大小写

2. 分词
   - 英文: spaCy / NLTK
   - 中文: jieba / pkuseg

3. 词表构建
   - 过滤低频词
   - 设定最大词表大小

4. 序列化
   - 编码为索引
   - 统一长度(填充/截断)

5. 数据增强(可选)
   - 同义词替换、回译

6. 批量加载
   - DataLoader + 自定义 collate_fn
Autres extensions