SentencePièce est un tokeniseur et détokeniseur de texte non supervisé principalement destiné aux systèmes de génération de texte basés sur un réseau neuronal où la taille du vocabulaire est prédéterminée avant la formation du modèle neuronal. SentencePièce implémente des unités de sous-mots (par exemple, le codage par paire d'octets (BPE) [Sennrich et al.]) et un modèle de langage unigramme [Kudo.]) avec l'extension de la formation directe à partir de phrases brutes. SentencePièce nous permet de créer un système purement de bout en bout qui ne dépend pas d'un pré/post-traitement spécifique au langage.
Ce n'est pas un produit Google officiel.
Pour ceux qui ne connaissent pas SentencePièce en tant que logiciel/algorithme, on peut lire une douce introduction ici.
Fonctionnalité | PhrasePièce | sous-mot-nmt | Morceau de mots |
---|---|---|---|
Algorithme pris en charge | BPE, unigramme, caractère, mot | EPB | EPB* |
OSS ? | Oui | Oui | Google interne |
Régularisation des sous-mots | Oui | Non | Non |
Bibliothèque Python (pip) | Oui | Non | N / A |
Bibliothèque C++ | Oui | Non | N / A |
Pré-segmentation requise ? | Non | Oui | Oui |
Normalisation personnalisable (par exemple, NFKC) | Oui | Non | N / A |
Génération d'identifiant direct | Oui | Non | N / A |
Notez que l'algorithme BPE utilisé dans WordPièce est légèrement différent du BPE d'origine.
SentencePièce est une réimplémentation d' unités de sous-mots , un moyen efficace d'atténuer les problèmes de vocabulaire ouvert dans la traduction automatique neuronale. SentencePièce prend en charge deux algorithmes de segmentation, le codage par paires d'octets (BPE) [Sennrich et al.] et le modèle de langage unigramme [Kudo.]. Voici les différences de haut niveau par rapport aux autres implémentations.
Les modèles de traduction automatique neuronale fonctionnent généralement avec un vocabulaire fixe. Contrairement à la plupart des algorithmes de segmentation de mots non supervisés, qui supposent un vocabulaire infini, SentencePièce entraîne le modèle de segmentation de telle sorte que la taille finale du vocabulaire soit fixe, par exemple 8k, 16k ou 32k.
Notez que SentencePièce spécifie la taille finale du vocabulaire pour la formation, qui est différente du sous-mot-nmt qui utilise le nombre d'opérations de fusion. Le nombre d'opérations de fusion est un paramètre spécifique à BPE et ne s'applique pas aux autres algorithmes de segmentation, notamment les unigrammes, les mots et les caractères.
Les implémentations précédentes de sous-mots supposent que les phrases d'entrée sont pré-tokénisées. Cette contrainte était nécessaire pour une formation efficace, mais rend le prétraitement compliqué car nous devons exécuter à l'avance des tokenizers dépendants de la langue. L'implémentation de SentencePièce est suffisamment rapide pour entraîner le modèle à partir de phrases brutes. Ceci est utile pour entraîner le tokenizer et le detokenizer pour le chinois et le japonais où aucun espace explicite n'existe entre les mots.
La première étape du traitement du langage naturel est la tokenisation du texte. Par exemple, un tokeniseur anglais standard segmenterait le texte « Hello world ». dans les trois jetons suivants.
[Bonjour le monde] [.]
Une observation est que l'entrée originale et la séquence tokenisée ne sont PAS convertibles de manière réversible . Par exemple, les informations qui ne comportent pas d'espace entre « Monde » et « ». est supprimé de la séquence tokenisée, puisque par exemple, Tokenize(“World.”) == Tokenize(“World .”)
SentencePièce traite le texte saisi comme une séquence de caractères Unicode. Les espaces sont également traités comme un symbole normal. Pour gérer explicitement les espaces comme jeton de base, SentencePièce échappe d'abord les espaces avec un méta-symbole " " (U+2581) comme suit.
Bonjour tout le monde.
Ensuite, ce texte est segmenté en petits morceaux, par exemple :
[Bonjour] [ Wor] [ld] [.]
Puisque les espaces sont préservés dans le texte segmenté, nous pouvons détokeniser le texte sans aucune ambiguïté.
detokenized = ''.join(pieces).replace('▁', ' ')
Cette fonctionnalité permet d'effectuer une détokenisation sans recourir à des ressources spécifiques à la langue.
Notez que nous ne pouvons pas appliquer les mêmes conversions sans perte lors du fractionnement de la phrase avec des segmenteurs de mots standard, car ils traitent les espaces comme un symbole spécial. Les séquences tokenisées ne préservent pas les informations nécessaires pour restaurer la phrase originale.
La régularisation des sous-mots [Kudo.] et l'abandon du BPE Provilkov et al sont des méthodes de régularisation simples qui augmentent virtuellement les données d'entraînement avec un échantillonnage de sous-mots à la volée, ce qui contribue à améliorer la précision ainsi que la robustesse des modèles NMT.
Pour activer la régularisation des sous-mots, vous souhaitez intégrer la bibliothèque SentencePièce (C++/Python) dans le système NMT pour échantillonner une segmentation pour chaque mise à jour de paramètre, ce qui est différent des préparations de données hors ligne standard. Voici l'exemple de la bibliothèque Python. Vous pouvez constater que « New York » est segmenté différemment sur chaque SampleEncode (C++)
ou encode with enable_sampling=True (Python)
. Les détails des paramètres d'échantillonnage se trouvent dans sentencepiece_processor.h.
>>> import sentencepiece as spm
>>> s = spm.SentencePieceProcessor(model_file='spm.model')
>>> for n in range(5):
... s.encode('New York', out_type=str, enable_sampling=True, alpha=0.1, nbest_size=-1)
...
['▁', 'N', 'e', 'w', '▁York']
['▁', 'New', '▁York']
['▁', 'New', '▁Y', 'o', 'r', 'k']
['▁', 'New', '▁York']
['▁', 'New', '▁York']
SentencePièce fournit un wrapper Python qui prend en charge à la fois la formation et la segmentation SentencePièce. Vous pouvez installer le package binaire Python de SentencePièce avec.
pip install sentencepiece
Pour plus de détails, voir le module Python
Les outils et bibliothèques suivants sont requis pour créer SentencePièce :
Sur Ubuntu, les outils de build peuvent être installés avec apt-get :
% sudo apt-get install cmake build-essential pkg-config libgoogle-perftools-dev
Ensuite, vous pouvez créer et installer des outils de ligne de commande comme suit.
% git clone https://github.com/google/sentencepiece.git
% cd sentencepiece
% mkdir build
% cd build
% cmake ..
% make -j $(nproc)
% sudo make install
% sudo ldconfig -v
Sous OSX/macOS, remplacez la dernière commande par sudo update_dyld_shared_cache
Vous pouvez télécharger et installer sentencepiece à l'aide du gestionnaire de dépendances vcpkg :
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install sentencepiece
Le port de phrase dans vcpkg est tenu à jour par les membres de l'équipe Microsoft et les contributeurs de la communauté. Si la version est obsolète, veuillez créer un problème ou une pull request sur le référentiel vcpkg.
Vous pouvez télécharger la roue depuis la page des versions de GitHub. Nous générons des signatures SLSA3 à l'aide du slsa-framework/slsa-github-generator d'OpenSSF pendant le processus de publication. Pour vérifier un binaire de version :
attestation.intoto.jsonl
à partir de la page des versions de GitHub.slsa-verifier -artifact-path < the-wheel > -provenance attestation.intoto.jsonl -source github.com/google/sentencepiece -tag < the-tag >
pip install wheel_file.whl
% spm_train --input=<input> --model_prefix=<model_name> --vocab_size=8000 --character_coverage=1.0 --model_type=<type>
--input
: fichier de corpus brut d'une phrase par ligne. Pas besoin d'exécuter un tokenizer, un normalizer ou un préprocesseur. Par défaut, SentencePièce normalise l'entrée avec Unicode NFKC. Vous pouvez transmettre une liste de fichiers séparés par des virgules.--model_prefix
: préfixe du nom du modèle de sortie. <model_name>.model
et <model_name>.vocab
sont générés.--vocab_size
: taille du vocabulaire, par exemple 8 000, 16 000 ou 32 000--character_coverage
: nombre de caractères couverts par le modèle, les bonnes valeurs par défaut sont : 0.9995
pour les langues avec un jeu de caractères riche comme le japonais ou le chinois et 1.0
pour les autres langues avec un jeu de caractères petit.--model_type
: type de modèle. Choisissez parmi unigram
(par défaut), bpe
, char
ou word
. La phrase d'entrée doit être pré-tokénisée lors de l'utilisation du type word
. Utilisez l'indicateur --help
pour afficher tous les paramètres de formation, ou voyez ici pour un aperçu.
% spm_encode --model=<model_file> --output_format=piece < input > output
% spm_encode --model=<model_file> --output_format=id < input > output
Utilisez l'indicateur --extra_options
pour insérer les marqueurs BOS/EOS ou inverser la séquence d'entrée.
% spm_encode --extra_options=eos (add </s> only)
% spm_encode --extra_options=bos:eos (add <s> and </s>)
% spm_encode --extra_options=reverse:bos:eos (reverse input and add <s> and </s>)
SentencePièce prend en charge la segmentation nbest et l'échantillonnage de segmentation avec --output_format=(nbest|sample)_(piece|id)
.
% spm_encode --model=<model_file> --output_format=sample_piece --nbest_size=-1 --alpha=0.5 < input > output
% spm_encode --model=<model_file> --output_format=nbest_id --nbest_size=10 < input > output
% spm_decode --model=<model_file> --input_format=piece < input > output
% spm_decode --model=<model_file> --input_format=id < input > output
Utilisez l'indicateur --extra_options
pour décoder le texte dans l'ordre inverse.
% spm_decode --extra_options=reverse < input > output
% spm_train --input=data/botchan.txt --model_prefix=m --vocab_size=1000
unigram_model_trainer.cc(494) LOG(INFO) Starts training with :
input: "../data/botchan.txt"
... <snip>
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=1100 obj=10.4973 num_tokens=37630 num_tokens/piece=34.2091
trainer_interface.cc(272) LOG(INFO) Saving model: m.model
trainer_interface.cc(281) LOG(INFO) Saving vocabs: m.vocab
% echo "I saw a girl with a telescope." | spm_encode --model=m.model
▁I ▁saw ▁a ▁girl ▁with ▁a ▁ te le s c o pe .
% echo "I saw a girl with a telescope." | spm_encode --model=m.model --output_format=id
9 459 11 939 44 11 4 142 82 8 28 21 132 6
% echo "9 459 11 939 44 11 4 142 82 8 28 21 132 6" | spm_decode --model=m.model --input_format=id
I saw a girl with a telescope.
Vous pouvez constater que la phrase d'entrée originale est restaurée à partir de la séquence d'identification du vocabulaire.
% spm_export_vocab --model=<model_file> --output=<output file>
<output file>
stocke une liste de vocabulaire et de probabilités de journal d'émission. L'identifiant du vocabulaire correspond au numéro de ligne de ce fichier.
Par défaut, la phrase utilise des jetons inconnus (<nek>), bos (<s>) et eos (</s>) qui ont respectivement les ID de 0, 1 et 2. Nous pouvons redéfinir cette cartographie dans la phase de formation comme suit.
% spm_train --bos_id=0 --eos_id=1 --unk_id=5 --input=... --model_prefix=... --character_coverage=...
Lors de la définition de -1 id, par exemple bos_id=-1
, ce jeton spécial est désactivé. Notez que l'identifiant inconnu ne peut pas être désactivé. Nous pouvons définir un identifiant pour le remplissage (<pad>) comme --pad_id=3
.
Si vous souhaitez attribuer d'autres jetons spéciaux, veuillez consulter Utiliser des symboles personnalisés.
spm_encode
accepte une option --vocabulary
et --vocabulary_threshold
afin que spm_encode
ne produise que des symboles qui apparaissent également dans le vocabulaire (avec au moins une certaine fréquence). L'arrière-plan de cette fonctionnalité est décrit dans la page subword-nmt.
L'utilisation est fondamentalement la même que celle de subword-nmt
. En supposant que L1 et L2 sont les deux langues (langues source/cible), entraînez le modèle spm partagé et obtenez le vocabulaire résultant pour chacune :
% cat {train_file}.L1 {train_file}.L2 | shuffle > train
% spm_train --input=train --model_prefix=spm --vocab_size=8000 --character_coverage=0.9995
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L1 > {vocab_file}.L1
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L2 > {vocab_file}.L2
La commande shuffle
est utilisée au cas où car spm_train
charge les 10 premiers millions de lignes du corpus par défaut.
Ensuite, segmentez le corpus d'entraînement/test avec l'option --vocabulary
% spm_encode --model=spm.model --vocabulary={vocab_file}.L1 --vocabulary_threshold=50 < {test_file}.L1 > {test_file}.seg.L1
% spm_encode --model=spm.model --vocabulary={vocab_file}.L2 --vocabulary_threshold=50 < {test_file}.L2 > {test_file}.seg.L2