<jupyter_start><jupyter_text>Пример работы с allennlpЗдесь мы разберем аналогичную модель, что мы писали на торче.<jupyter_code>import torch
from src_allennlp.model import SimpleTagger
from src_allennlp.reader import RuPosReader
from allennlp.data.vocabulary import Vocabulary
from allennlp.common import Params
from allennlp.modules.text_field_embedders import BasicTextFieldEmbedder
from allennlp.modules.token_embedders import Embedding
from allennlp.modules.seq2seq_encoders import PytorchSeq2SeqWrapper
from allennlp.data.iterators import BucketIterator
from allennlp.training.trainer import Trainer<jupyter_output><empty_output><jupyter_text>Из всех импортов тут только два самописных класса - ридер и, собственно, сама модель.<jupyter_code>reader = RuPosReader()
dataset = reader.read('data/train.csv')
vocab = Vocabulary.from_instances(dataset, pretrained_files={'tokens':'data/cc.ru.300.vec'}, only_include_pretrained_words=False)
print(vocab)
print(vocab.get_index_to_token_vocabulary('labels'))<jupyter_output>48171it [00:03, 12951.79it/s]
100%|█████████████████████████████████████████████████████████████████████████| 48171/48171 [00:00<00:00, 52064.41it/s]
100%|████████████████████████████████████████████████████████████████████| 2000000/2000000 [00:15<00:00, 127662.48it/s]<jupyter_text>В ячейке выше мы прочитали датасет и сделали из него словарь<jupyter_code>word_emb = 300
hidden_dim = 300

params = Params({"pretrained_file": 'data/cc.ru.300.vec', "embedding_dim": word_emb, "trainable": False})
embedder = BasicTextFieldEmbedder({"tokens": Embedding.from_params(vocab, params)})
encoder = PytorchSeq2SeqWrapper(torch.nn.GRU(embedder.get_output_dim(), hidden_dim, batch_first=True, bidirectional=True, num_layers=2))
model = SimpleTagger(vocab, embedder, encoder)<jupyter_output>100%|█████████████████████████████████████████████████████████████████████| 2000000/2000000 [00:26<00:00, 76039.26it/s]<jupyter_text>Наша модель состоит из:- эмбеддера, возвращающего векторные представления для каждого токена- энкодера, который представляет собой всё ту же GRU, как и раньше, только всякими неудобными вещами занимется `PytorchSeq2SeqWrapper`.- FeedForward, который уже встроен в модель, но его можно и передать отдельно, предварительно поддержав в самой модели в конструкторе<jupyter_code>train_dataset = dataset[:-1000]
dev_dataset = dataset[-1000:]<jupyter_output><empty_output><jupyter_text>Распиливаем датасет, слайсы здесь работают нормально<jupyter_code>device = torch.device('cuda')
model.to(device)
optimizer = torch.optim.Adam(model.parameters())
iterator = BucketIterator(batch_size=256, sorting_keys=[("tokens", "num_tokens")], biggest_batch_first=True)
iterator.index_with(vocab)
trainer = Trainer(model=model,
                  optimizer=optimizer,
                  iterator=iterator,
                  train_dataset=train_dataset,
                  validation_dataset=dev_dataset,
                  patience=5,
                  num_epochs=20,
                  cuda_device=0,
                  validation_metric="+fscore")<jupyter_output><empty_output><jupyter_text>Переносим модель на видеокарту, задаём оптимизатор, итератор с индексированием по словарю и сам тренер. У тренера есть куча удобных параметров, например, сколько эпох учить, через сколько эпох остановиться, если таргетная метрика перестаёт расти на валидации (`patience`) и собственно сама таргетная метрика, по которой будет выбираться лучшая эпоха<jupyter_code>trainer.train()<jupyter_output>accuracy: 0.7411, precision: 0.7411, recall: 0.7411, fscore: 0.7411, loss: 0.8184 ||: 100%|█| 185/185 [00:13<00:00, 13.
accuracy: 0.9293, precision: 0.9293, recall: 0.9293, fscore: 0.9293, loss: 0.2344 ||: 100%|█| 4/4 [00:00<00:00, 23.73it
accuracy: 0.9436, precision: 0.9436, recall: 0.9436, fscore: 0.9436, loss: 0.1905 ||: 100%|█| 185/185 [00:11<00:00, 16.
accuracy: 0.9540, precision: 0.9540, recall: 0.9540, fscore: 0.9540, loss: 0.1566 ||: 100%|█| 4/4 [00:00<00:00, 29.06it
accuracy: 0.9560, precision: 0.9560, recall: 0.9560, fscore: 0.9560, loss: 0.1469 ||: 100%|█| 185/185 [00:11<00:00, 16.
accuracy: 0.9635, precision: 0.9635, recall: 0.9635, fscore: 0.9635, loss: 0.1276 ||: 100%|█| 4/4 [00:00<00:00, 29.93it
accuracy: 0.9614, precision: 0.9614, recall: 0.9614, fscore: 0.9614, loss: 0.1262 ||: 100%|█| 185/185 [00:11<00:00, 16.
accuracy: 0.9665, precision: 0.9665, recall: 0.9665, fscore: 0.9665, loss: 0.1163 ||: 100%|█| 4/4 [00:00<00:00, 29.93it
accuracy: 0.9652, precision: 0.9652, rec[...]<jupyter_text>После обучения модели остаётся только предстказать метки классов и можно заворачивать<jupyter_code>model.eval()
results = []
with torch.no_grad():    
    labels =  model.forward_on_instance(dev_dataset[1])['labels']<jupyter_output><empty_output><jupyter_text>Сам по себе инстанс это что-то похожее на словарь, поэтому чтобы добраться до токенов, нужно немного пройти по словарю<jupyter_code>for token, label in zip(dev_dataset[1]['tokens'].tokens,labels):
    print(token, label)<jupyter_output>Сегодня ADV
Великий ADJ
Октябрь NOUN
прибавил VERB
к ADP
своей DET
биографии NOUN
еще ADV
один NUM
год NOUN
. PUNCT
{'fraction_non_alphanumeric': 0.15651834504293521, 'fraction_numerical': 0.09699453551912568, 'mean_word_length': 6.059228650137741, 'pattern_counts': {'":': 4, '<': 40, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '422826', 'license': 'MIT', 'n_tokens_mistral': 2479, 'n_tokens_neox': 2151, 'n_words': 413, 'path': 'pos_allennlp.ipynb', 'repo_name': 'ASEDOS999/Morphology', 'size': '5124'}