Spaces:
Runtime error
Runtime error
import streamlit as st | |
# !pip install -q transformers | |
import numpy as np | |
# import pandas as pd | |
import re | |
# import random | |
import torch | |
# from tqdm.notebook import tqdm | |
import transformers | |
# from torch.optim import AdamW | |
import textwrap | |
# Загружаем токенайзер модели | |
from transformers import GPT2Tokenizer | |
tokenizer = GPT2Tokenizer.from_pretrained('sberbank-ai/rugpt3small_based_on_gpt2') | |
# import re | |
with open('anekdoty.txt', encoding='utf8') as f: | |
text = f.read() | |
text = re.sub('\n{2,}', '\n', text) | |
print(text[:1000]) | |
# токенизируем текст | |
tokens = tokenizer.encode(text, add_special_tokens=True) | |
tokens = np.array(tokens) | |
print(len(tokens)) | |
tokens[:10] | |
# разбиваем на train и test | |
l = len(tokens)//15 | |
train = [] | |
test = [] | |
for i in range(15): | |
if i%5 > 0: | |
train.extend(tokens[i*l: (i+1)*l]) | |
else: | |
test.extend(tokens[i*l: (i+1)*l]) | |
train = np.array(train) | |
test = np.array(test) | |
print(len(tokens), len(train), len(test)) | |
from transformers import GPT2LMHeadModel | |
# Эту модель просто подгружаем и не будем дообучать | |
model_init = GPT2LMHeadModel.from_pretrained( | |
'sberbank-ai/rugpt3small_based_on_gpt2', | |
output_attentions = False, | |
output_hidden_states = False, | |
) | |
# Эту модель подгрузим и далее обучим | |
model = GPT2LMHeadModel.from_pretrained( | |
'sberbank-ai/rugpt3small_based_on_gpt2', | |
output_attentions = False, | |
output_hidden_states = False, | |
) | |
model.to(device); | |
model_init.to(device); | |
batch_size = 8 | |
max_len = 256 | |
epochs = 5 | |
n_train = len(train)//(batch_size*max_len) | |
n_test = len(test)//(batch_size*max_len) | |
print(n_train, n_test) | |
# устанавливаем оптимизатор | |
optimizer = AdamW(model.parameters(), lr = 1e-5, eps = 1e-8) | |
# трансформеры с трудом обучаются, для них нужны разные способы повышения | |
# эффективности градиентного спуска | |
total_steps = n_train * epochs | |
scheduler = transformers.get_linear_schedule_with_warmup(optimizer, | |
num_warmup_steps = 0, | |
num_training_steps = total_steps) | |
# зададим точность, хотя ориентироваться будем на качество генерации | |
def accuracy(y_true, logits): | |
return torch.mean((y_true[1:] == torch.argmax(logits, dim=2)[:-1]).float()).detach().cpu().numpy() | |
# готовим тензоры для обучения размера [batch_size, max_len] | |
def prep_tensors(x, i, batch_size=batch_size, max_len=max_len): | |
batch_ids = x[i*batch_size*max_len: (i+1)*batch_size*max_len] | |
batch_ids = batch_ids.reshape(batch_size, max_len) | |
batch_ids = torch.tensor(batch_ids).to(device) | |
return batch_ids | |
# обучающий цикл | |
for epoch in range(1, epochs+1): | |
print(f'epoch {epoch}/{epochs} : training') | |
train_loss = [] | |
train_acc = [] | |
model.train() | |
pbar = range(n_train) | |
# pbar = tqdm(range(n_train)) | |
for i in pbar: | |
batch_ids = prep_tensors(train, i) | |
model.zero_grad() | |
loss, logits, _ = model(batch_ids, | |
token_type_ids=None, | |
labels=batch_ids | |
).values() | |
loss.backward() | |
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) | |
optimizer.step() | |
scheduler.step() | |
train_loss.append(loss.item()) | |
train_acc.append(accuracy(batch_ids, logits)) | |
print(f'acc {np.mean(train_acc):.4f} loss {np.mean(train_loss):.4f}') | |
# pbar.set_description(f'acc {np.mean(train_acc):.4f} loss {np.mean(train_loss):.4f}', refresh=True) | |
print(f'epoch {epoch}/{epochs} : validation') | |
model.eval() | |
val_acc = [] | |
val_loss = [] | |
pbar = range(n_test) | |
# pbar = tqdm(range(n_test)) | |
for i in pbar: | |
batch_ids = prep_tensors(test, i) | |
with torch.no_grad(): | |
loss, logits, _ = model(batch_ids, | |
token_type_ids=None, | |
labels=batch_ids | |
).values() | |
val_loss.append(loss.item()) | |
val_acc.append(accuracy(batch_ids, logits)) | |
print(f'acc {np.mean(val_acc):.4f} loss {np.mean(val_loss):.4f}') | |
# pbar.set_description(f'acc {np.mean(val_acc):.4f} loss {np.mean(val_loss):.4f}', refresh=True) | |
# Применим модель, которую мы не дообучали: просто для понимания разницы между дообученной на собственных данных моделью и предобученной. | |
# https://huggingface.co/transformers/main_classes/model.html#transformers.generation_utils.GenerationMixin.generate | |
# модель без дообучения | |
# prompt – строка, которую модель примет на вход и продолжит | |
prompt = 'Мужик спрашивает официанта' | |
# токенизируем строку | |
prompt = tokenizer.encode(prompt, return_tensors='pt').to(device) | |
# out будет содержать результаты генерации в виде списка | |
out = model_init.generate( | |
# входная строка | |
input_ids=prompt, | |
# максимальная длина генерируемой последовательности | |
max_length=250, | |
# num_beams | |
num_beams=5, | |
# применяем сэмплирование | |
do_sample=True, | |
# применяем температуру | |
temperature=55., | |
# топ слов по вероятности | |
top_k=50, | |
# топ слов по суммарной вероятности | |
top_p=0.6, | |
# сколько (постараться) не повторять n_gram подряд | |
no_repeat_ngram_size=3, | |
# сколько вернуть генераций | |
num_return_sequences=7, | |
).cpu().numpy() | |
# out содержит результаты | |
# декодируем и печатаем | |
for out_ in out: | |
print(tokenizer.decode(out_)) | |
# дообученная модель | |
with torch.inference_mode(): | |
prompt = 'Мужик спрашивает официанта' | |
prompt = tokenizer.encode(prompt, return_tensors='pt').to(device) | |
out = model.generate( | |
input_ids=prompt, | |
max_length=150, | |
num_beams=1, | |
do_sample=True, | |
temperature=1., | |
top_k=5, | |
top_p=0.6, | |
no_repeat_ngram_size=2, | |
num_return_sequences=7, | |
).cpu().numpy() | |
for out_ in out: | |
print(textwrap.fill(tokenizer.decode(out_), 100), end='\n------------------\n') | |
# Сохраняем веса обученной модели | |
torch.save(model.state_dict(), 'model.pt') | |
# Задаем класс модели (уже в streamlit/tg_bot) | |
model_finetuned = GPT2LMHeadModel.from_pretrained( | |
'sberbank-ai/rugpt3small_based_on_gpt2', | |
output_attentions = False, | |
output_hidden_states = False, | |
) | |
# Вешаем сохраненные веса на нашу модель | |
model = model_finetuned.load_state_dict(torch.load('model.pt')) | |
# -> <All keys matched successfully> |