Используя инструмент конвейера HuggingFace, я с удивлением обнаружил, что значительная разница в выводе при использовании быстрого и медленного токенизатора.
В частности, когда я запускаю конвейер маски заполнения, вероятности, присвоенные словам, которые будут заполнять маску, не одинаковы для быстрого и медленного токенизатора. Более того, хотя прогнозы быстрого токенизатора остаются постоянными независимо от количества и длины вводимых предложений, то же самое не верно для медленного токенизатора.
Вот минимальный пример:
from transformers import pipeline
slow = pipeline('fill-mask', model='bert-base-cased', \
tokenizer=('bert-base-cased', {"use_fast": False}))
fast = pipeline('fill-mask', model='bert-base-cased', \
tokenizer=('bert-base-cased', {"use_fast": True}))
s1 = "This is a short and sweet [MASK]." # "example"
s2 = "This is [MASK]." # "shorter"
slow([s1, s2])
fast([s1, s2])
slow([s2])
fast([s2])
Каждый вызов конвейера дает пять токенов, которые могут заполнить [MASK]
, вместе с их вероятностями. Я опустил фактические результаты для краткости, но вероятности, присвоенные каждому слову, которое заменяет [MASK]
вместо s2
, не одинаковы во всех примерах. Последние 3 примера дают одинаковые вероятности, но первый дает разные вероятности. Различия настолько велики, что топ-5 не совпадают по двум группам.
Причина этого, насколько я могу судить, в том, что быстрые и медленные токенизаторы возвращают разные выходные данные. Быстрый токенизатор стандартизирует длину последовательности до 512, заполняя нулями, а затем создает маску внимания, которая блокирует заполнение. Напротив, медленный токенизатор заполняет только самую длинную последовательность и не создает такую маску внимания. Вместо этого он устанавливает идентификатор типа токена для заполнения равным 1 (а не 0, который является типом токенов без заполнения). Насколько я понимаю, реализация HuggingFace (найдена здесь) не эквивалент.
Кто-нибудь знает, намеренно ли это?