Как узнать, какие слова закодированы неизвестными токенами в HuggingFace BertTokenizer?

Я использую следующий код, чтобы подсчитать, сколько % слов закодировано в неизвестные токены.

paragraph_chinese = '...' # It is a long paragraph from a text file.
from transformers import AutoTokenizer, BertTokenizer
tokenizer_bart = BertTokenizer.from_pretrained("fnlp/bart-base-chinese")
encoded_chinese_bart = tokenizer_bart.encode(paragraph_chinese)
unk_token_id_bart = tokenizer_bart.convert_tokens_to_ids(["[UNK]"])
len_paragraph_chinese   = len(paragraph_chinese)

unk_token_cnt_chinese_bart   = encoded_chinese_bart.count(unk_token_id_bart[0])
print("BART Unknown Token count in Chinese Paragraph:", unk_token_cnt_chinese_bart, "(" + str(unk_token_cnt_chinese_bart * 100 / len_paragraph_chinese) + "%)")
print(type(tokenizer_bart))

который печатает:

BART Unknown Token count in Chinese Paragraph: 1 (0.015938795027095953%)
<class 'transformers.models.bert.tokenization_bert.BertTokenizer'>

Мой вопрос: я заметил один неизвестный токен. Как я могу узнать, какое слово вызывает этот неизвестный токен?

п.с. Я попробовал print(encoded_chinese_bart), но это список идентификаторов токенов.

Используя transformers 4.28.1

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
158
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Когда вы используете BertTokenizerFast вместо «медленной» версии, вы получаете объект BatchEncoding, который дает вам доступ к нескольким удобным методам, позволяющим сопоставить токен обратно с исходной строкой.

В следующем коде используется метод token_to_chars:

from transformers import BertTokenizerFast

# just an example
paragraph_chinese = '马云 Kočka 祖籍浙江省嵊县 Kočka 现嵊州市' 

tokenizer_bart = BertTokenizerFast.from_pretrained("fnlp/bart-base-chinese")
encoded_chinese_bart = tokenizer_bart(paragraph_chinese)
unk_token_id_bart = tokenizer_bart.unk_token_id
len_paragraph_chinese   = len(paragraph_chinese)

unk_token_cnt_chinese_bart   = encoded_chinese_bart.input_ids.count(unk_token_id_bart)
print(f'BART Unknown Token count in Chinese Paragraph: {unk_token_cnt_chinese_bart} ({unk_token_cnt_chinese_bart * 100 / len_paragraph_chinese}%)')

#find all indices
unk_indices = [i for i, x in enumerate(encoded_chinese_bart.input_ids) if x == unk_token_id_bart]
for unk_i in unk_indices:
  start, stop = encoded_chinese_bart.token_to_chars(unk_i)
  print(f"At {start}:{stop}: {paragraph_chinese[start:stop]}")

Оригинал:

BART Unknown Token count in Chinese Paragraph: 2 (7.407407407407407%)
At 3:8: Kočka
At 17:22: Kočka

Было бы здорово, если бы значения не были жестко закодированы.

Raptor 26.04.2024 04:16

@Raptor Я обновил свой ответ, добавив переменные.

cronoik 11.05.2024 14:35

Основываясь на ответе от cronoik, я написал свою собственную реализацию langchain_text_splitter.TokenTextSplitter для tranformers.BertTokenizerFast. Он использует исходный текст напрямую, сохраняя неизвестные слова (не заменяя их на [UNK]).


from typing import Any

from langchain_text_splitters import TextSplitter
from transformers import BertTokenizerFast
from transformers.tokenization_utils_base import VERY_LARGE_INTEGER


class CustomTokenTextSplitter(TextSplitter):
    """Splitting text to tokens using model tokenizer."""

    def __init__(
        self,
        tokenizer: BertTokenizerFast,
        chunk_size: int,
        **kwargs: Any,
    ) -> None:
        """Create a new TextSplitter."""
        super().__init__(**kwargs, chunk_size=chunk_size)

        self.tokenizer = tokenizer

    def split_text(self, text: str) -> list[str]:
        return split_text_on_tokens(
            text=text, chunk_size=self._chunk_size, chunk_overlap=self._chunk_overlap, tokenizer=self.tokenizer
        )


def split_text_on_tokens(*, text: str, chunk_size: int, chunk_overlap: int, tokenizer: BertTokenizerFast):
    """Split incoming text and return chunks using tokenizer."""
    splits = []
    tokenization = tokenizer(text, add_special_tokens=False, truncation=False, max_length=VERY_LARGE_INTEGER)
    input_ids = tokenization["input_ids"]
    assert len(tokenization.encodings) <= 1, "Should be Only one encoding"
    encodings = tokenization.encodings[0]
    start_idx = 0
    cur_idx = min(start_idx + chunk_size, len(input_ids))

    while start_idx < len(input_ids):
        start, _ = encodings.token_to_chars(start_idx)
        _, end = encodings.token_to_chars(cur_idx - 1)
        splits.append(text[start:end])
        if cur_idx == len(input_ids):
            break
        start_idx += chunk_size - chunk_overlap
        cur_idx = min(start_idx + chunk_size, len(input_ids))

    return splits

Другие вопросы по теме