Обработка неизвестных слов при создании моделей NER

Вопрос или проблема

Я работаю над своей моделью распознавания именованных сущностей, которую создаю с помощью библиотеки Keras на Python. Я прочитал, что мне нужно перечислить все слова, которые появляются, чтобы получить векторизованные последовательности. Я сделал это таким образом:

word2idx = {w: i + 1 for i, w in enumerate(words)}
label2idx = {t: i for i, t in enumerate(labels)}

# СОЗДАНИЕ ПРИЗНАКОВ(X) И РЕЗУЛЬТАТОВ(Y)
max_len = 50 
num_words = len(num_words) # количество уникальных слов в наборе данных
X = [[word2idx[w[0]] for w in s] for s in list_of_sentances]
X = pad_sequences(maxlen=max_len, sequences=X, padding="post", value=num_words-1)

y = [[label2idx[w[1]] for w in s] for s in list_of_sentances]
y = pad_sequences(maxlen=max_len, sequences=y, padding="post", value=label2idx["O"])
y = [to_categorical(i, num_classes=num_labels) for i in y]

Это моя финальная модель:

input_word = Input(shape=(max_len,))

model = Embedding(input_dim = num_words, output_dim = 50, input_length = max_len)(input_word)
model = SpatialDropout1D(0.2)(model)
model = Bidirectional(LSTM(units = 5, return_sequences=True, recurrent_dropout = 0.1))(model)
out = TimeDistributed(Dense(num_labels, activation = "softmax"))(model)

model = Model(input_word, out)
model.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 30)]              0         
_________________________________________________________________
embedding (Embedding)        (None, 30, 50)            2187550   
_________________________________________________________________
spatial_dropout1d (SpatialDr (None, 30, 50)            0         
_________________________________________________________________
bidirectional (Bidirectional (None, 30, 10)            2240      
_________________________________________________________________
time_distributed (TimeDistri (None, 30, 11)            121       
=================================================================
Всего параметров: 2,189,911  #ОБРАЩАЙТЕ ВНИМАНИЕ НА ЭТО ЧИСЛО
Обучаемые параметры: 2,189,911
Необучаемые параметры: 0

Моя точность составляет 98%, а потери — 0,07. Мне нравятся эти результаты, но у меня есть проблема с предсказанием из-за отсутствующих слов. Например:

text = "Я живу в Огайо, и меня зовут Алекс Райта, и я работаю в AvcCC LTD"
text = text.split()
text = [word2idx[w] for w in text]

text = np.array(text)
print(text)
text = text.reshape(1, text.shape[0])

max_len = 50
text = pad_sequences(maxlen=max_len, sequences=text, padding="post", value=num_words-1)
print('ПРЕДСКАЗАНИЕ')
res = model.predict(text).argmax(axis=-1)[0]
print(res)

ОШИБКА:

KeyError: 'AvcCC'

В моем наборе данных и словаре нет слова ‘AvcCC’, как с этим справиться?

Я хочу использовать этот код/модель в производстве. Поскольку мой word2idx содержит только слова, которые были в исходных данных, как мне обрабатывать слова, которые не находятся в моем словаре word2idx? Например, невозможно, чтобы мой словарь word2idx содержал все имена и фамилии, которые существуют, или все названия городов/локаций, все названия компаний, сленговые слова и т.д.

Мой словарь имел около 40 тысяч перечисленных слов (это количество уникальных слов в моем наборе данных). Затем я обогатил его более чем 100 тысячами других слов. (Я создал веб-сканер, который просматривал различные типы новостных статей). Теперь мой словарь содержит около 140 тысяч слов. Теперь, вместо того, чтобы перечислять уникальные слова из набора данных, я загружаю мой новый word2idx/словарь.

word2idx = open('english-vocab.json')
word2idx = json.load(word2idx)

max_len = 50 
num_words = len(num_words) # количество уникальных слов в наборе данных
X = [[word2idx[w[0]] for w in s] for s in list_of_sentances]
X = pad_sequences(maxlen=max_len, sequences=X, padding="post", value=num_words-1)

y = [[label2idx[w[1]] for w in s] for s in list_of_sentances]
y = pad_sequences(maxlen=max_len, sequences=y, padding="post", value=label2idx["O"])
y = [to_categorical(i, num_classes=num_labels) for i in y]

Точность и потери остались прежними, но моя модель стала намного медленнее из-за Total params (я больше не могу использовать num_words, потому что это вызывает ошибку, я должен использовать len(word2idx))

input_word = Input(shape=(max_len,))

model = Embedding(input_dim = len(word2idx), output_dim = 50, input_length = max_len)(input_word)
model = SpatialDropout1D(0.2)(model)
model = Bidirectional(LSTM(units = 5, return_sequences=True, recurrent_dropout = 0.1))(model)
out = TimeDistributed(Dense(num_labels, activation = "softmax"))(model)

model = Model(input_word, out)
model.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         [(None, 30)]              0         
_________________________________________________________________
embedding_1 (Embedding)      (None, 30, 50)            5596600   
_________________________________________________________________
spatial_dropout1d_1 (Spatial (None, 30, 50)            0         
_________________________________________________________________
bidirectional_1 (Bidirection (None, 30, 10)            2240      
_________________________________________________________________
time_distributed_1 (TimeDist (None, 30, 11)            121       
=================================================================
Всего параметров: 7,598,961 # ГОРАЗДО БОЛЬШЕЕ ЧИСЛО
Обучаемые параметры: 5,598,961
Необучаемые параметры: 0

Создав свой собственный word2idx, я хотел справиться с отсутствующими словами в словаре, но единственное, что я сделал, это замедлил обучение своей модели.

Как мне справиться с этой проблемой? Как работать с отсутствующими/несуществующими/неизвестными словами?

Неизвестные слова являются неотъемлемой частью внедрения моделей NLP в производство. Я рекомендую рассмотреть эти методы:

  1. удаление неизвестных – самый тривиальный способ справиться с неизвестными словами – просто удалить их. Это не оптимально по тривиальным причинам, так что давайте продолжим.
  2. неизвестный тег – добавьте новое слово в ваш словарь, которое будет представлять неизвестные слова, вы можете назвать его [UNK]. Рекомендуется заменять некоторые редкие слова во время обучения на [UNK] для повышения надежности.
  3. символы – работать на уровне символов вместо уровня слов.
  4. BPE – алгоритм, который позволяет вам разбивать слова на подсоставляющие умным способом и не оставляет неизвестных слов. Вы получаете лучшее из обоих миров – уровень слов, уровень символов, а теперь также и уровень подсослов.

Каждый из этих методов имеет свои плюсы и минусы, и я рекомендую подробнее почитать о них.

Существуют различные методы обработки слов, такие как использование UNK, кодирование символов, кодирование подсослов и кодирование пар байтов. Давайте посмотрим, как использовать каждый из них в следующих фрагментах кода.

  1. Замена на UNK: Чтобы использовать это, просто добавьте UNK или неизвестное слово в свой словарь т.е. в список слов. Когда вы сталкиваетесь с неузнанным словом, замените его на UNK или неизвестный идентификатор.

например, text = [word2idx.get(w, word2idx.get(‘UNK’)) for w in text]

  1. Кодирование подсослов: Это немного отличается от word2vec и glove, которые рассматривают слово как наименьшую сущность, но алгоритмы, такие как Fasttext, разбивают редкие слова на подсоставляющие, чтобы вычислить его вектор на основе Skipgram и CBOW.

например, проверьте реализацию fasttext на Python и поиграйте с ней, чтобы получить представление

  1. Кодирование пар байтов: BPE немного модифицирован в своей реализации таким образом, что часто встречающиеся пары подсослов объединяются вместо того, чтобы заменяться другим байтом для обеспечения сжатия. BPE немного модифицирован в своей реализации таким образом, что часто встречающиеся пары подсослов объединяются вместо того, чтобы заменяться другим байтом для обеспечения сжатия.

например, проверьте библиотеку huggingface для ее реализации, так как Transformers использует BPE.

Ответ или решение

Обработка неведомых слов при создании моделей распознавания именованных сущностей (NER)

Создание модели распознавания именованных сущностей (NER) может быть сложной задачей, особенно когда речь идет о работе с неизвестными или неведомыми словами. Ваша модель показывает отличные результаты в плане точности и потерь, однако, сталкиваясь с новыми или редкими словами, вы получаете ошибку. Рассмотрим, как можно эффективно обрабатывать такие слова, чтобы улучшить качество работы вашей модели в производственной среде.

1. Введение в проблему

Как вы уже заметили, ошибка KeyError: 'AvcCC' возникает из-за того, что слово, которое вы пытаетесь ввести в модель, отсутствует в вашем word2idx словаре. Это естественный недостаток, когда объем лексики не может охватить все возможные слова, особенно имена, компании и неформальные термины.

2. Подходы к обработке неизвестных слов

Существует несколько подходов для обработки неизвестных слов, каждый из которых имеет свои плюсы и минусы:

2.1 Удаление неизвестных слов

Наиболее простой способ — просто удалить слова, которые не известны модели. Это не оптимально, так как может привести к потере контекстной информации.

2.2 Использование метки для неизвестных слов

Добавьте в словарь специальный токен, например [UNK] (например, "неизвестное"). При обработке текста, если слово отсутствует в word2idx, замените его на [UNK]. Это может улучшить устойчивость модели.

text = [word2idx.get(w, word2idx['UNK']) for w in text]
2.3 Работа с символами

Работа на уровне символов может быть эффективной, особенно для языков с сложной морфологией. Вместо работы с целыми словами, вы можете представлять слова как последовательности символов, что позволяет вашей модели справляться с неведомыми словами.

2.4 Использование подсловных единиц

Применение алгоритма BPE (Byte Pair Encoding) может помочь разделить слова на подкомпоненты, не оставляя неизвестных слов. Это дает лучшее сочетание работы на уровне слов и символов, а также позволяет более эффективно моделировать значения редких слов.

2.5 FastText

Используйте модели, такие как FastText, которые разбивают редкие слова на подслова и позволяют создать векторы из них. Это может помочь вашей модели вспомнить значения редких или неизвестных слов, опираясь на их составные части.

3. Реализация методов

Чтобы внедрить данные методы, необходимо начальное определение предобработанной последовательности слов, включая добавление токена [UNK]:

# Обновите ваш словарь
word2idx['UNK'] = len(word2idx)  # добавляем 'UNK' как последний токен

# Обработка текста
text = [word2idx.get(w, word2idx['UNK']) for w in text]

Также можно использовать FastText:

from gensim.models import FastText

# Обучить FastText на коре текстов, а затем получать векторы
model = FastText(sentences, vector_size=100, window=3, min_count=1)  
vector = model.wv['AvcCC']  # Получите вектор для 'AvcCC', даже если оно не встречалось ранее

Заключение

Решение проблемы обработки неизвестных слов является ключевым этапом в подготовке вашей модели для использования в производственной среде. Методы, такие как использование токенов для неизвестных слов, работа на уровне символов или применение BPE и FastText, могут значительно увеличить точность и устойчивость вашей модели. Выбор подхода зависит от специфики данной задачи и доступных данных, поэтому рекомендуем протестировать несколько методов и проанализировать их влияние на качество ваших прогнозов.

Оцените материал
Добавить комментарий

Капча загружается...