2 заметки с тегом

fastText

Определение языка текста на Python

Для задач NLP бывает полезно предварительно определить язык текста с которым мы сейчас работаем.

Например, это может пригодиться в случае, если:

  1. Какая-то наша модель умеет работать корректно только с определенным набором языков
  2. Для каждого языка у нас есть отдельная модель
  3. Текст на разных языках нужно по разному подготавливать: выбрать нужный стеммер или токенайзер — особенно важно для китайского и японского языков.

В работе я использую для решения этой задачи три библиотеки: fastText от Facebook, Compact Language Detector v3 от Google и langdetect. У каждой из них свои преимущества и недостатки связанные с размерами моделей, скоростью работы и точностью. Но, в целом, судя по опыту, точнее всего работает именно fastText.

Для задачи определения языка у fastText есть две готовые модели: побольше, на 126 мб и поменьше, на 917 кб. Вторая будет менее точная, но обе поддерживают одинаковое количество языков — 176 штук.

Качаем обе и посмотрим как с ними работать:


wget https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin
wget https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.ftz

Загружаем обе модели:


import fastText

model_big = fastText.load_model('./lid.176.bin')
model_small = fastText.load_model('./lid.176.ftz')

Пробуем в работе:


print(model.predict(["hi"]))
print(model_small.predict(["hi"]))

И получаем довольно странный результат:


([['__label__ca']], [array([0.5109927], dtype=float32)])
([['__label__en']], [array([0.12450418], dtype=float32)])

Почему так? Библиотека настроена на работу с предложениями, а не с отдельными словами, поэтому точность на очень коротких текстах будет хромать. Хотя, забавно, что маленькая модель сработала тут лучше, чем большая. Попробуем с текстом подлиннее:


print(model.predict(["hi there, human"]))
print(model_small.predict(["hi there, human"]))

И получаем вполне приемлемый результат:


([['__label__en']], [array([0.84252757], dtype=float32)])
([['__label__en']], [array([0.83792776], dtype=float32)])

Когда использовать какую модель из двух? Это зависит от желаемой точности и скорости работы. Если важнее точность, то можно использовать большую модель, а если скорость, то маленькую. Главное, если мы применяем определение языка в пайплайне обучения, например, классификатора спама, использовать, по возможности, ту же самую модель и в продакшне. А то итоговое качество может сильно хромать.

 Нет комментариев    794   2021   fastText   NLP   Python

fastText эмбеддинги

fastText — библиотека для векторного представления слов и классификации текстов от Facebook AI Research.

Для её сборки, нам потребуется компилятор с поддержкой C++11 (gcc-4.6.3, clang-3.3 и новее):

git clone https://github.com/facebookresearch/fastText.git
cd fastText
sudo python3 -m pip install .

Если у вас установлено несколько компиляторов разных версий, то можно запустить установку, явно указав путь к нужной версии компилятора:

sudo CC='/usr/bin/gcc-4.9' python3 -m pip install .

Используем уже натренированную модель

Тренированную модель для русского языка можно скачать тут. В архиве занимает 4.2 Гб, распакованная 6.8 Гб:

wget https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.ru.300.bin.gz
gunzip cc.ru.300.bin.gz

Использовать можно так:

from fasttext import load_model

model = load_model("cc.ru.300.bin")

Тренируем свою модель

from fasttext import train_unsupervised

model = train_unsupervised(
    input="dataset.txt", 
    model='skipgram'
)

model.save_model("skipgram_model.bin")

На Core i7-6700 с датасетом в 20 млн строк, модель обучилась в течении 5 эпох за 35 минут и весила ~1.1 Гб.

Используем

Для оценки похожести/близости векторов будем использовать косинусное сходство:

$$ \mathrm{similarity} = \mathrm{cos(}\theta\mathrm{)} = \dfrac{A \cdot B}{\left\lVert A \right\rVert \cdot \left\lVert B \right\rVert}  $$

В коде будет выглядеть так:

import numpy as np

def similarity(v1, v2):
    n1 = np.linalg.norm(v1)
    n2 = np.linalg.norm(v2)

    if n1 < 1e-6 or n2 < 1e-6:
        return 0.0
    else:
        return np.dot(v1, v2) / n1 / n2

def word_similarity(model, w1, w2):
    return similarity(model.get_word_vector(w1), model.get_word_vector(w2))

def sentence_similarity(model, t1, t2):
    return similarity(model.get_sentence_vector(t1), model.get_sentence_vector(t2))

Проверяем:

>>> word_similarity(model, "приветик", "привет")
0.7990662

>>> sentence_similarity(model, "сколько тебе лет", "а лет-то тебе сколько")
0.85209394

Про классификацию текста при помощи fastText напишу чуть позже.