Deep-learning based NLP modeling for Russian language
Project description
SlovNet is a Python library for deep-learning based NLP modeling for Russian language. Library is integrated with other Natasha projects: Nerus — large automatically annotated corpus, Razdel — sentence segmenter, tokenizer and Navec — compact Russian embeddings. SlovNet provides high quality practical models for Russian NER and morphology. NER is 1-2% worse than current BERT SOTA by DeepPavlov but 60 times smaller in size (~30 MB) and works fast on CPU (~25 news articles/sec). Morphology tagger has comparable accuracy on news dataset with large SOTA BERT models, takes 50 times less space (~30 MB), works faster on CPU (~500 sentences/sec). See evaluation section for more.
Downloads
Model | Size | Description |
---|---|---|
slovnet_ner_news_v1.tar | 2MB | Russian NER, standart PER, LOC, ORG annotation, trained on news articles. |
slovnet_morph_news_v1.tar | 2MB | Russian morphology tagger optimized for news articles. |
slovnet_syntax_news_v1.tar | 3MB | Russian syntax parser optimized for news articles. |
Install
During inference Slovnet depends only on Numpy. Library supports Python 3.5+, PyPy 3.
$ pip install slovnet
Usage
Download model weights and vocabs package, use links from downloads section and Navec download section. Optionally install Ipymarkup to visualize NER markup.
Slovnet annotators have list of items as input and same size iterator over markups as output. Internally items are processed in batches of size batch_size
. Default size is 8, larger batch — more RAM, better CPU utilization.
NER
>>> from navec import Navec
>>> from slovnet import NER
>>> from ipymarkup import show_span_ascii_markup as show_markup
>>> text = 'Европейский союз добавил в санкционный список девять политических деятелей из самопровозглашенных республик Донбасса — Донецкой народной республики (ДНР) и Луганской народной республики (ЛНР) — в связи с прошедшими там выборами. Об этом говорится в документе, опубликованном в официальном журнале Евросоюза. В новом списке фигурирует Леонид Пасечник, который по итогам выборов стал главой ЛНР. Помимо него там присутствуют Владимир Бидевка и Денис Мирошниченко, председатели законодательных органов ДНР и ЛНР, а также Ольга Позднякова и Елена Кравченко, председатели ЦИК обеих республик. Выборы прошли в непризнанных республиках Донбасса 11 ноября. На них удержали лидерство действующие руководители и партии — Денис Пушилин и «Донецкая республика» в ДНР и Леонид Пасечник с движением «Мир Луганщине» в ЛНР. Президент Франции Эмманюэль Макрон и канцлер ФРГ Ангела Меркель после встречи с украинским лидером Петром Порошенко осудили проведение выборов, заявив, что они нелегитимны и «подрывают территориальную целостность и суверенитет Украины». Позже к осуждению присоединились США с обещаниями новых санкций для России.'
>>> navec = Navec.load('navec_news_v1_1B_250K_300d_100q.tar')
>>> ner = NER.load('slovnet_ner_news_v1.tar')
>>> ner.navec(navec)
>>> markup = ner(text)
>>> show_markup(markup.text, markup.spans)
Европейский союз добавил в санкционный список девять политических
LOC─────────────
деятелей из самопровозглашенных республик Донбасса — Донецкой народной
LOC───── LOC──────────────
республики (ДНР) и Луганской народной республики (ЛНР) — в связи с
───────────────── LOC────────────────────────────────
прошедшими там выборами. Об этом говорится в документе, опубликованном
в официальном журнале Евросоюза. В новом списке фигурирует Леонид
LOC────── PER────
Пасечник, который по итогам выборов стал главой ЛНР. Помимо него там
──────── LOC
присутствуют Владимир Бидевка и Денис Мирошниченко, председатели
PER───────────── PER───────────────
законодательных органов ДНР и ЛНР, а также Ольга Позднякова и Елена
LOC LOC PER───────────── PER───
Кравченко, председатели ЦИК обеих республик. Выборы прошли в
───────── ORG
непризнанных республиках Донбасса 11 ноября. На них удержали лидерство
LOC─────
действующие руководители и партии — Денис Пушилин и «Донецкая
PER────────── ORG──────
республика» в ДНР и Леонид Пасечник с движением «Мир Луганщине» в ЛНР.
────────── LOC PER──────────── ORG────────── LOC
Президент Франции Эмманюэль Макрон и канцлер ФРГ Ангела Меркель после
LOC──── PER───────────── LOC PER───────────
встречи с украинским лидером Петром Порошенко осудили проведение
PER─────────────
выборов, заявив, что они нелегитимны и «подрывают территориальную
целостность и суверенитет Украины». Позже к осуждению присоединились
LOC────
США с обещаниями новых санкций для России.
LOC LOC───
Morphology
Morphology annotator processes tokenized text. To split the input into sentencies and tokens use Razdel.
>>> from razdel import sentenize, tokenize
>>> from navec import Navec
>>> from slovnet import Morph
>>> chunk = []
>>> for sent in sentenize(text):
>>> tokens = [_.text for _ in tokenize(sent.text)]
>>> chunk.append(tokens)
>>> chunk[:1]
[['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей', 'из', 'самопровозглашенных', 'республик', 'Донбасса', '—', 'Донецкой', 'народной', 'республики', '(', 'ДНР', ')', 'и', 'Луганской', 'народной', 'республики', '(', 'ЛНР', ')', '—', 'в', 'связи', 'с', 'прошедшими', 'там', 'выборами', '.']]
>>> navec = Navec.load('navec_news_v1_1B_250K_300d_100q.tar')
>>> morph = Morph.load('slovnet_morph_news_v1.tar', batch_size=4)
>>> morph.navec(navec)
>>> markup = next(morph.map(chunk))
>>> for token in markup.tokens:
>>> print(f'{token.text:>20} {token.tag}')
Европейский ADJ|Case=Nom|Degree=Pos|Gender=Masc|Number=Sing
союз NOUN|Animacy=Inan|Case=Nom|Gender=Masc|Number=Sing
добавил VERB|Aspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Act
в ADP
санкционный ADJ|Animacy=Inan|Case=Acc|Degree=Pos|Gender=Masc|Number=Sing
список NOUN|Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing
девять NUM|Case=Nom
политических ADJ|Case=Gen|Degree=Pos|Number=Plur
деятелей NOUN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Plur
из ADP
самопровозглашенных ADJ|Case=Gen|Degree=Pos|Number=Plur
республик NOUN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Plur
Донбасса PROPN|Animacy=Inan|Case=Gen|Gender=Masc|Number=Sing
— PUNCT
Донецкой ADJ|Case=Gen|Degree=Pos|Gender=Fem|Number=Sing
народной ADJ|Case=Gen|Degree=Pos|Gender=Fem|Number=Sing
республики NOUN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing
( PUNCT
ДНР PROPN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing
) PUNCT
и CCONJ
Луганской ADJ|Case=Gen|Degree=Pos|Gender=Fem|Number=Sing
народной ADJ|Case=Gen|Degree=Pos|Gender=Fem|Number=Sing
республики NOUN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing
( PUNCT
ЛНР PROPN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing
) PUNCT
— PUNCT
в ADP
связи NOUN|Animacy=Inan|Case=Loc|Gender=Fem|Number=Sing
с ADP
прошедшими VERB|Aspect=Perf|Case=Ins|Number=Plur|Tense=Past|VerbForm=Part|Voice=Act
там ADV|Degree=Pos
выборами NOUN|Animacy=Inan|Case=Ins|Gender=Masc|Number=Plur
. PUNCT
Syntax
Syntax parser processes sentencies split into tokens. Use Razdel for segmentation.
>>> from ipymarkup import show_dep_ascii_markup as show_markup
>>> from razdel import sentenize, tokenize
>>> from navec import Navec
>>> from slovnet import Syntax
>>> chunk = []
>>> for sent in sentenize(text):
>>> tokens = [_.text for _ in tokenize(sent.text)]
>>> chunk.append(tokens)
>>> chunk[:1]
[['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей', 'из', 'самопровозглашенных', 'республик', 'Донбасса', '—', 'Донецкой', 'народной', 'республики', '(', 'ДНР', ')', 'и', 'Луганской', 'народной', 'республики', '(', 'ЛНР', ')', '—', 'в', 'связи', 'с', 'прошедшими', 'там', 'выборами', '.']]
>>> navec = Navec.load('navec_news_v1_1B_250K_300d_100q.tar')
>>> syntax = Syntax.load('slovnet_syntax_news_v1.tar')
>>> syntax.navec(navec)
>>> markup = next(syntax.map(chunk))
# Convert CoNLL-style format to source, target indices
>>> words, deps = [], []
>>> for token in markup.tokens:
>>> words.append(token.text)
>>> source = int(token.head_id) - 1
>>> target = int(token.id) - 1
>>> if source > 0 and source != target: # skip root, loops
>>> deps.append([source, target, token.rel])
>>> show_markup(words, deps)
┌► Европейский amod
┌►└─ союз nsubj
┌───────┌─┌─└─── добавил
│ │ │ ┌──► в case
│ │ │ │ ┌► санкционный amod
│ │ └►└─└─ список obl
│ │ ┌──► девять nummod:gov
│ │ │ ┌► политических amod
│ ┌─────└►┌─└─└─ деятелей obj
│ │ │ ┌──► из case
│ │ │ │ ┌► самопровозглашенных amod
│ │ └►└─└─ республик nmod
│ │ └──► Донбасса nmod
│ │ ┌──────────► — punct
│ │ │ ┌──► Донецкой amod
│ │ │ │ ┌► народной amod
│ │ │ ┌─┌─┌─└─└─ республики
│ │ │ │ │ │ ┌► ( punct
│ │ │ │ │ └►┌─└─ ДНР parataxis
│ │ │ │ │ └──► ) punct
│ │ │ │ │ ┌────► и cc
│ │ │ │ │ │ ┌──► Луганской amod
│ │ │ │ │ │ │ ┌► народной amod
│ │ └─│ └►└─└─└─ республики conj
│ │ │ ┌► ( punct
│ │ └────►┌─└─ ЛНР parataxis
│ │ └──► ) punct
│ │ ┌──────► — punct
│ │ │ ┌►┌─┌─ в case
│ │ │ │ │ └► связи fixed
│ │ │ │ └──► с fixed
│ │ │ │ ┌►┌─ прошедшими acl
│ │ │ │ │ └► там advmod
│ └────►└─└─└─── выборами nmod
└──────────────► . punct
Evaluation
In addition to quality metrics we measure speed and models size, parameters that are important in practise:
init
— time between system launch and first response. It is convenient for testing and devops to have model that starts quickly.disk
— file size of artefacts one needs to download before using the system: model weights, embeddings, binaries, vocabs. It is inconvenient to deploy large models in production.ram
— average CPU/GPU RAM usage.speed
— number of input items processed per second: news article texts, tokenized sentencies.
NER
4 datasets are used for evaluation, see Corus registry for more info: factru
, gareev
, ne5
and bsnlp
. slovnet
is compared to:
deeppavlov
— biLSTM + CRF by DeepPavlov, see their 2017 paper for more.deeppavlov_bert
— BERT based NER, current SOTA for Russian language, see video presentation describing the approach.pullenti
— first place on factRuEval-2016, super sophisticated ruled based system.texterra
— multifunctional NLP solution by ISP RAS, NER is one of the features.tomita
— GLR-parser by Yandex, only grammars forPER
are publicly available.mitie
— engine developed at MIT + third party model for Russian language.
For every column top 3 results are highlighted. In each case slovnet
and deeppavlov_bert
are 5-10% better then other systems:
factru | gareev | ne5 | bsnlp | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
f1 | PER | LOC | ORG | PER | ORG | PER | LOC | ORG | PER | LOC | ORG |
slovnet_bert | 0.973 | 0.928 | 0.831 | 0.991 | 0.911 | 0.996 | 0.989 | 0.976 | 0.960 | 0.838 | 0.733 |
slovnet | 0.959 | 0.915 | 0.825 | 0.977 | 0.899 | 0.984 | 0.973 | 0.951 | 0.944 | 0.834 | 0.718 |
deeppavlov | 0.910 | 0.886 | 0.742 | 0.944 | 0.798 | 0.942 | 0.919 | 0.881 | 0.866 | 0.767 | 0.624 |
deeppavlov_bert | 0.971 | 0.928 | 0.825 | 0.980 | 0.916 | 0.997 | 0.990 | 0.976 | 0.954 | 0.840 | 0.741 |
pullenti | 0.905 | 0.814 | 0.686 | 0.939 | 0.639 | 0.952 | 0.862 | 0.683 | 0.900 | 0.769 | 0.566 |
texterra | 0.900 | 0.800 | 0.597 | 0.888 | 0.561 | 0.901 | 0.777 | 0.594 | 0.858 | 0.783 | 0.548 |
tomita | 0.929 | 0.921 | 0.945 | 0.881 | |||||||
natasha | 0.867 | 0.753 | 0.297 | 0.873 | 0.347 | 0.852 | 0.709 | 0.394 | 0.836 | 0.755 | 0.350 |
mitie | 0.888 | 0.861 | 0.532 | 0.849 | 0.452 | 0.753 | 0.642 | 0.432 | 0.736 | 0.801 | 0.524 |
init, s | disk, mb | ram, mb | speed, it/s | |
---|---|---|---|---|
slovnet_bert | 5.0 | 473 | 9500 | 40.0 (gpu) |
slovnet | 1.0 | 27 | 205 | 25.3 |
deeppavlov | 5.9 | 1024 | 3072 | 24.3 (gpu) |
deeppavlov_bert | 34.5 | 2048 | 6144 | 13.1 (gpu) |
pullenti | 2.9 | 16 | 253 | 6.0 |
texterra | 47.6 | 193 | 3379 | 4.0 |
tomita | 2.0 | 64 | 63 | 29.8 |
natasha | 2.0 | 1 | 160 | 8.8 |
mitie | 28.3 | 327 | 261 | 32.8 |
Morphology
Datasets from GramEval2020 are used for evaluation. slovnet
is compated to a number of existing morphology taggers:
deeppavlov
anddeeppavlov_bert
— Char biLSTM and BERT based models, see Deeppavlov docs.rupostagger
rnnmorph
— first place on morphoRuEval-2017.maru
udpipe
— UDPipe with model trained on SynTagRus.spacy
— spaCy with Russian models trained by @buriy.
For every column top 3 results are highlighted. slovnet
was trained only on news dataset:
news | wiki | fiction | social | poetry | |
---|---|---|---|---|---|
rupostagger | 0.673 | 0.645 | 0.661 | 0.641 | 0.636 |
rnnmorph | 0.896 | 0.812 | 0.890 | 0.860 | 0.838 |
maru | 0.894 | 0.808 | 0.887 | 0.861 | 0.840 |
udpipe | 0.918 | 0.811 | 0.957 | 0.870 | 0.776 |
spacy | 0.919 | 0.812 | 0.938 | 0.836 | 0.729 |
deeppavlov | 0.940 | 0.841 | 0.944 | 0.870 | 0.857 |
deeppavlov_bert | 0.951 | 0.868 | 0.964 | 0.892 | 0.865 |
slovnet | 0.961 | 0.815 | 0.905 | 0.807 | 0.664 |
slovnet_bert | 0.982 | 0.884 | 0.990 | 0.890 | 0.856 |
init, s | disk, mb | ram, mb | speed, it/s | |
---|---|---|---|---|
rupostagger | 4.8 | 3 | 118 | 48.0 |
rnnmorph | 8.7 | 10 | 289 | 16.6 |
maru | 15.8 | 44 | 370 | 36.4 |
udpipe | 6.9 | 45 | 242 | 56.2 |
spacy | 10.9 | 89 | 579 | 30.6 |
deeppavlov | 4.0 | 32 | 10240 | 90.0 (gpu) |
deeppavlov_bert | 20.0 | 1393 | 8704 | 85.0 (gpu) |
slovnet | 1.0 | 27 | 115 | 532.0 |
slovnet_bert | 5.0 | 475 | 8087 | 285.0 (gpu) |
Syntax
udpipe
— UDPipe + Russian SynTagRus model.spacy
— spaCy + Russian models by @buriy.deeppavlov_bert
— BERT + biaffine head, see Deeppavlov docs.
news | wiki | fiction | social | poetry | ||||||
---|---|---|---|---|---|---|---|---|---|---|
uas | las | uas | las | uas | las | uas | las | uas | las | |
udpipe | 0.873 | 0.823 | 0.622 | 0.531 | 0.910 | 0.876 | 0.700 | 0.624 | 0.625 | 0.534 |
spacy | 0.876 | 0.818 | 0.770 | 0.665 | 0.880 | 0.833 | 0.757 | 0.666 | 0.657 | 0.544 |
deeppavlov_bert | 0.962 | 0.910 | 0.882 | 0.786 | 0.963 | 0.929 | 0.844 | 0.761 | 0.784 | 0.691 |
slovnet_bert | 0.965 | 0.936 | 0.891 | 0.828 | 0.958 | 0.940 | 0.846 | 0.782 | 0.776 | 0.706 |
slovnet | 0.907 | 0.880 | 0.775 | 0.718 | 0.806 | 0.776 | 0.726 | 0.656 | 0.542 | 0.469 |
init, s | disk, mb | ram, mb | speed, it/s | |
---|---|---|---|---|
udpipe | 6.9 | 45 | 242 | 56.2 |
spacy | 10.9 | 89 | 579 | 31.6 |
deeppavlov_bert | 34.0 | 1427 | 8704 | 75.0 (gpu) |
slovnet_bert | 5.0 | 504 | 3427 | 200.0 (gpu) |
slovnet | 1.0 | 27 | 125 | 450.0 |
Support
- Chat — https://telegram.me/natural_language_processing
- Issues — https://github.com/natasha/slovnet/issues
Development
Tests:
make test
Package:
make version
git push
git push --tags
make clean package publish
Rent GPU:
yc compute instance create \
--name gpu \
--zone ru-central1-a \
--network-interface subnet-name=default,nat-ip-version=ipv4 \
--create-boot-disk image-folder-id=standard-images,image-family=ubuntu-1804-lts-ngc,type=network-ssd,size=20 \
--cores=8 \
--memory=96 \
--gpus=1 \
--ssh-key ~/.ssh/id_rsa.pub \
--folder-name default \
--platform-id gpu-standard-v1 \
--preemptible
yc compute instance list
yc compute instance delete fhmj2ftcm32qgqt4igjf
Setup instance:
sudo locale-gen ru_RU.UTF-8
sudo apt-get update
sudo apt-get install -y \
python3-pip
# grpcio long install ~10m, not using prebuilt wheel
# "it is not compatible with this Python"
sudo pip3 install -v \
jupyter \
tensorboard
mkdir runs
nohup tensorboard \
--logdir=runs \
--host=localhost \
--port=6006 \
--reload_interval=1 &
nohup jupyter notebook \
--no-browser \
--allow-root \
--ip=localhost \
--port=8888 \
--NotebookApp.token='' \
--NotebookApp.password='' &
ssh -Nf gpu -L 8888:localhost:8888 -L 6006:localhost:6006
scp ~/.slovnet.json gpu:~
rsync --exclude data -rv . gpu:~/slovnet
rsync -u --exclude data -rv 'gpu:~/slovnet/*' .
Intall dev:
pip3 install -r slovnet/requirements/dev.txt
pip3 install -e slovnet
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.