[PYTHON] Calculez la correspondance entre deux divisions

Lors du traitement d'une langue, je pense qu'elle est souvent divisée à l'aide d'un tokenizer tel que mecab. Dans cet article, je vais vous présenter comment calculer la correspondance entre les différentes sorties de tokenizer (écriture séparée) et son implémentation (tokenisations). Par exemple, regardons la méthode suivante qui ne dépend pas de l'implémentation du tokenizer et calcule la correspondance entre le résultat de la division du morceau de phrase et BERT.

#Partage
(a) BERT          : ['Fu', '##Helt', '##Nous', '##Fuルク', 'Traité', 'À', 'Conclusion']
(b) sentencepiece : ['▁', 'Fu', 'Cloche', 'À nous', 'Burg', 'Traité', 'À', 'Conclusion']

#Correspondance
a2b: [[1], [2, 3], [3], [4], [5], [6], [7]]
b2a: [[], [0], [1], [1, 2], [3], [4], [5], [6]]

problème

En regardant l'exemple précédent, vous pouvez voir qu'il existe les différences suivantes entre les différentes divisions.

  1. Comment couper des jetons est différent
  2. Normalisation différente (par exemple B-> F)
  3. Le bruit tel que les caractères de contrôle peuvent entrer (exemple: #, _)

Si la différence n'est que de 1, cela semble facile à gérer. Vous pouvez comparer les deux divisions un caractère à la fois à partir du haut. En fait, le spacy.gold.align (lien) précédemment implémenté dans spaCy compare les fractions de cette façon. Cependant, dès que 2 et 3 arrivent, cela devient déroutant. S'il est correct de s'appuyer sur l'implémentation de chaque tokenizer, il semble possible de calculer la correspondance en excluant les caractères de contrôle, mais l'implémenter de cette façon pour toute combinaison de tokenizers peut être intimidant. spacy-transformers a répondu à ce problème en ignorant tous les caractères sauf ascii. /blob/88814f5f4be7f0d4c784d8500c558d9ba06b9a56/spacy_transformers/_tokenizers.py#L539) est adopté. Il semble que cela fonctionne assez bien en anglais, mais cela ne fonctionne guère en japonais. Par conséquent, le problème à résoudre cette fois est de calculer la correspondance des ensembles divisionnaires avec les différences 1 à 3 ci-dessus.

Normalisation

Diverses normalisations sont utilisées dans le traitement du langage. Par exemple

Etc. En plus de celui ci-dessus, il est souvent utilisé en combinaison. Par exemple, le modèle multilingue BERT utilise abaissement + NFKD + suppression d'accent.

Méthode de calcul correspondante

Soit les deux divisions «A» et «B». Par exemple, ʻA = ["Aujourd'hui", "est", "Bon", "Météo", "Da"] `. La correspondance peut être calculée comme suit.

  1. Normaliser chaque jeton avec NFKD et le réduire
  2. Combinez les jetons «A» et «B» pour former deux chaînes «Sa» et «Sb». (Exemple: «Sa =« C'est une belle journée aujourd'hui »»)
  3. Calculez le chemin le plus court sur le graphique d'édition de Sa et Sb
  4. Suivez le chemin le plus court pour obtenir la correspondance entre les caractères «Sa» et «Sb»
  5. Calculer la correspondance des jetons à partir de la correspondance des caractères

En bref, après une bonne normalisation, l'inverse de diff est utilisé pour prendre la correspondance de caractère et calculer la correspondance de jeton. La clé est 3, qui peut être calculée de la même manière que la distance d'édition DP, par exemple en utilisant l'algorithme de Myers à faible coût. Je vais. NFKD a été adopté en 1. car le jeu de caractères après normalisation est le plus petit parmi la normalisation Unicode. En d'autres termes, le taux de réussite peut être augmenté autant que possible. Par exemple, "bu" et "fu" peuvent être partiellement pris en charge par NFKD, mais pas par NFKC.

>>> a = unicodedata.normalize("NFKD", "Fu")
>>> b = unicodedata.normalize("NFKD", "Bu")
>>> print(a in b)
True
>>> a = unicodedata.normalize("NFKC", "Fu")
>>> b = unicodedata.normalize("NFKC", "Bu")
>>> print(a in b)
False

la mise en oeuvre

L'implémentation est publiée ici: GitHub: tamuhey / tokenizations

C'est Rust, mais il fournit également des liaisons Python. La bibliothèque Python peut être utilisée comme suit.

$ pip install pytokenizations
>>> import tokenizations
>>> tokens_a = ['Fu', '##Helt', '##Nous', '##Fuルク', 'Traité', 'À', 'Conclusion']
>>> tokens_b = ['▁', 'Fu', 'Cloche', 'À nous', 'Burg', 'Traité', 'À', 'Conclusion']
>>> a2b, b2a = tokenizations.get_alignments(tokens_a, tokens_b)
>>> print(a2b)
[[1], [2, 3], [3], [4], [5], [6], [7]]
>>> print(b2a)
[[], [0], [1], [1, 2], [3], [4], [5], [6]]

À la fin

L'autre jour, j'ai sorti une bibliothèque de traitement de langage appelée Camphr, et j'utilise beaucoup les «pytokénisations» dans cette bibliothèque. Il s'agit de calculer la correspondance entre les transformateurs et spaCy. Cela facilite la combinaison des deux bibliothèques et élimine le besoin d'écrire du code pour chaque modèle. C'est sobre, mais je pense que c'est une fonction très utile en utilisation pratique.

Recommended Posts

Calculez la correspondance entre deux divisions
Examiner la relation entre deux variables (2)
Calculez le décalage horaire entre deux colonnes avec Pandas DataFrame
Estimer le délai entre deux signaux
Examiner la relation entre deux variables (1)
Calculer l'angle entre les vecteurs à n dimensions avec TensorFlow
Modélisation-estimation de Bayes de la différence entre les deux groupes-
Différentes façons de calculer la similitude entre les données avec python
Calculez le nombre de changements
Calculez la similitude entre les phrases avec Doc2Vec, une évolution de Word2Vec