Spaces:
Sleeping
Sleeping
import torch | |
import nltk | |
nltk.download('stopwords') | |
import os | |
import numpy as np | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import re | |
import string | |
from collections import Counter | |
from nltk.corpus import stopwords | |
import streamlit as st | |
import torch | |
from torch.utils.data import DataLoader, TensorDataset | |
import torch.nn as nn | |
import torchutils as tu | |
from dataclasses import dataclass | |
russian_stopwords = stopwords.words("russian") | |
from dataclasses import dataclass | |
import json | |
import time | |
with open('pages/models/vocab_to_int.json', 'r') as json_file: | |
json_data = json_file.read() | |
vocab_to_int = json.loads(json_data) | |
def data_preprocessing(text: str) -> str: | |
"""preprocessing string: lowercase, removing html-tags, punctuation and stopwords | |
Args: | |
text (str): input string for preprocessing | |
Returns: | |
str: preprocessed string | |
""" | |
text = text.lower() | |
text = re.sub("<.*?>", "", text) # html tags | |
text = "".join([c for c in text if c not in string.punctuation]) | |
splitted_text = [word for word in text.split() if word not in russian_stopwords] | |
text = " ".join(splitted_text) | |
return text | |
def padding(review_int: list, seq_len: int) -> np.array: | |
"""Make left-sided padding for input list of tokens | |
Args: | |
review_int (list): input list of tokens | |
seq_len (int): max length of sequence, it len(review_int[i]) > seq_len it will be trimmed, else it will be padded by zeros | |
Returns: | |
np.array: padded sequences | |
""" | |
features = np.zeros((36591, seq_len), dtype=int) | |
for i, review in enumerate(review_int): | |
if len(review) <= seq_len: | |
zeros = list(np.zeros(seq_len - len(review))) | |
new = zeros + review | |
else: | |
new = review[:seq_len] | |
features[i, :] = np.array(new) | |
return features | |
def preprocess_single_string( | |
input_string: str, | |
seq_len: int, | |
vocab_to_int: dict = vocab_to_int | |
) -> torch.Tensor: | |
"""Function for all preprocessing steps on a single string | |
Args: | |
input_string (str): input single string for preprocessing | |
seq_len (int): max length of sequence, it len(review_int[i]) > seq_len it will be trimmed, else it will be padded by zeros | |
vocab_to_int (dict, optional): word corpus {'word' : int index}. Defaults to vocab_to_int. | |
Returns: | |
list: preprocessed string | |
""" | |
preprocessed_string = data_preprocessing(input_string) | |
result_list = [] | |
for word in preprocessed_string.split(): | |
try: | |
result_list.append(vocab_to_int[word]) | |
except KeyError as e: | |
print(f'{e}: not in dictionary!') | |
result_padded = padding([result_list], seq_len)[0] | |
return torch.Tensor(result_padded) | |
class RNNNet(nn.Module): | |
''' | |
vocab_size: int, размер словаря (аргумент embedding-слоя) | |
emb_size: int, размер вектора для описания каждого элемента последовательности | |
hidden_dim: int, размер вектора скрытого состояния, default 0 | |
batch_size: int, размер batch'а | |
''' | |
def __init__( | |
self, | |
vocab_size: int, | |
emb_size: int, | |
hidden_dim: int, | |
seq_len: int, | |
n_layers: int = 1 | |
) -> None: | |
super().__init__() | |
self.seq_len = seq_len | |
self.emb_size = emb_size | |
self.hidden_dim = hidden_dim | |
self.n_layers = n_layers | |
self.vocab_size = vocab_size | |
self.embedding = nn.Embedding(self.vocab_size, self.emb_size) | |
self.rnn_cell = nn.RNN( | |
input_size = self.emb_size, | |
hidden_size = self.hidden_dim, | |
batch_first = True, | |
num_layers = n_layers | |
) | |
self.linear = nn.Sequential( | |
nn.Linear(self.hidden_dim * self.seq_len, 16), | |
nn.Tanh(), | |
nn.Linear(16, 3) | |
) | |
def forward(self, x: torch.Tensor) -> torch.Tensor: | |
# self.input = x.size(0) | |
x = self.embedding(x.to(rnn_conf.device)) | |
output, _ = self.rnn_cell(x) | |
# print(f'RNN output: {output.shape}') | |
output = output.contiguous().view(output.size(0), -1) | |
# print(f'Flatten output: {output.shape}') | |
out = self.linear(output.squeeze(0)) | |
return out | |
SEQ_LEN = 100 | |
class ConfigRNN: | |
vocab_size: int | |
device : str | |
n_layers : int | |
embedding_dim : int | |
hidden_size : int | |
seq_len : int | |
rnn_conf = ConfigRNN( | |
vocab_size = len(vocab_to_int)+1, | |
device='cpu', | |
n_layers=1, | |
embedding_dim=8, | |
hidden_size=16, | |
seq_len = SEQ_LEN | |
) | |
rnn_model = RNNNet( | |
vocab_size=rnn_conf.vocab_size, | |
emb_size=rnn_conf.embedding_dim, | |
hidden_dim=rnn_conf.hidden_size, | |
seq_len=rnn_conf.seq_len, | |
n_layers=rnn_conf.n_layers | |
) | |
rnn_model.load_state_dict(torch.load("pages/models/weights.pt")) | |
result = {1: "Нейтральный", 2: "Положительный", 0: "Отрицательный" } | |
# rnn_model.eval() | |
# probability = rnn_model(preprocess_single_string('Сказать, что я разочарован — ничего не сказать. Сценаристу за адаптацию шедевральной книги Р. Д. Уоллера надо что-нибудь оторвать. Нелогичные поступки, из-за невозможности перенести на экран мысли людей (не можешь не берись, на самом деле). Важные мысли и сцены из книги убраны, добавлены новые, ни к селу. Все хорошее в сценарии — из книги. Все нелепое — от сценариста. Да и затянуть до 2,15 часа короткую книгу тоже не лучший ход.\n\nК кастингу тоже вопросы. Мэрис Стрип прекрасная актриса, но Франческа — итальянка, и Стрип пришлось прибегать к ужимкам в стиле Маргариты Тереховой, что меня просто коробило. С Иствудом отдельная тема. При прочтении именно Иствуд («Роберт был высокий, худой и сильный, а двигался, как трава под ветром, плавно, без усилий. Серебристо-седые волосы прикрывали уши и шею, и, надо сказать, выглядел он всегда слегка растрепанным, как будто только что сошел на землю после путешествия по бурному морю и пытался ладонью привести волосы в порядок. Узкое лицо, высокие скулы и лоб, наполовину прикрытый волосами, на фоне которых голубые глаза смотрелись особенно ярко.») выглядел идеальным актером на роль Кинкейда. Но вот беда — Иствуд постарел. Играть в 65 пятидесятилетнего мужчину нелегко. Лет десять назад было бы намного лучше.\n\nНу и режиссура. Слабо, к сожалению. Очень поверхностно. Получилась простенькая мелодрама. А жаль, книга более чем достойная.', seq_len=SEQ_LEN).unsqueeze(0).long().to(rnn_conf.device)).sigmoid() | |
# print(f'{result[torch.argmax(probability).item()]} Вероятность: {probability.max():.3f}') | |
def pred(text): | |
start_time = time.time() | |
probability = rnn_model(preprocess_single_string(text, seq_len=SEQ_LEN).unsqueeze(0).long().to(rnn_conf.device)).sigmoid() | |
end_time = time.time() | |
inference_time = end_time - start_time | |
return f' RNN {result[torch.argmax(probability).item()]} {inference_time} секунд' | |