Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import pandas as pd | |
| import streamlit as st | |
| import pickle | |
| import time | |
| from typing import Tuple | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| import transformers | |
| import numpy as np | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.metrics import f1_score | |
| import torch | |
| from transformers import AutoTokenizer, AutoModel | |
| from torch.utils.data import TensorDataset, DataLoader | |
| from sklearn.preprocessing import LabelEncoder | |
| import re | |
| import string | |
| import numpy as np | |
| import torch.nn as nn | |
| import json | |
| import gensim | |
| import torch.nn.functional as F | |
| from transformers import GPT2LMHeadModel, GPT2Tokenizer | |
| from transformers import AutoModelForSequenceClassification | |
| st.title('10-я неделя DS. Классификация отзывов, определение токсичности и генерация текста') | |
| st.sidebar.header('Выберите страницу') | |
| page = st.sidebar.radio("Выберите страницу", ["Вводная информация", "Классификация отзывов", "Зоопарк моделей и F1-score", "Определение токсичности", "Генерация текста"]) | |
| if page == "Вводная информация": | |
| st.subheader('*Задача №1*: Классификация отзывов на медицинские учреждения') | |
| st.write('Задача в двух словах: необходимо дать классификацию отзыва тремя моделями, время, за которое происходит классификаци отзыва, а также таблицу сравнения моделей по F-1 macro для моделей') | |
| st.subheader('*Задача №2*: Определение токсичности') | |
| st.write('Задача в двух словах: Оценка степени токсичности пользовательского сообщения ') | |
| st.subheader('*Задача №3*: Генерация текста') | |
| st.write('Задача в двух словах: Генерация текста GPT-моделью по пользовательскому prompt') | |
| st.subheader('☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️') | |
| st.subheader('Выполнила команда "BERT": Алексей А., Светлана, Алиса') | |
| if page == "Классификация отзывов": | |
| # Загрузка tf-idf модели и векторайзера | |
| with open('tf-idf/tf-idf.pkl', 'rb') as f: | |
| model_tf = pickle.load(f) | |
| with open('tf-idf/tf-idf_vectorizer.pkl', 'rb') as f: | |
| vectorizer_tf = pickle.load(f) | |
| # Загрузка словаря vocab_to_int и Word2Vec модели | |
| with open('lstm/vocab_to_int.json', 'r') as f: | |
| vocab_to_int = json.load(f) | |
| word2vec_model = gensim.models.Word2Vec.load("lstm/word2vec.model") | |
| stop_words = ['и', 'в', 'во', 'не', 'что', 'он', 'на', 'я', 'с', 'со', 'как', 'а', 'то', 'все', 'она', 'так', 'его', 'но', 'да', 'ты', 'к', 'у', 'же', 'вы', 'за', 'бы', 'по', 'только', 'ее', 'мне', 'было', 'вот', 'от', 'меня', 'еще', 'нет', 'о', 'из', 'ему', 'теперь', 'когда', 'даже', 'ну', 'вдруг', 'ли', 'если', 'уже', 'или', 'ни', 'быть', 'был', 'него', 'до', 'вас', 'нибудь', 'опять', 'уж', 'вам', 'ведь', 'там', 'потом', 'себя', 'ничего', 'ей', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней', 'для', 'мы', 'тебя', 'их', 'чем', 'была', 'сам', 'чтоб', 'без', 'будто', 'чего', 'раз', 'тоже', 'себе', 'под', 'будет', 'ж', 'тогда', 'кто', 'этот', 'того', 'потому', 'этого', 'какой', 'совсем', 'ним', 'здесь', 'этом', 'один', 'почти', 'мой', 'тем', 'чтобы', 'нее', 'сейчас', 'были', 'куда', 'зачем', 'всех', 'никогда', 'можно', 'при', 'наконец', 'два', 'об', 'другой', 'хоть', 'после', 'над', 'больше', 'тот', 'через', 'эти', 'нас', 'про', 'всего', 'них', 'какая', 'много', 'разве', 'три', 'эту', 'моя', 'впрочем', 'хорошо', 'свою', 'этой', 'перед', 'иногда', 'лучше', 'чуть', 'том', 'нельзя', 'такой', 'им', 'более', 'всегда', 'конечно', 'всю', 'между'] | |
| def data_preprocessing(text: str) -> str: | |
| text = text.lower() | |
| text = re.sub('<.*?>', '', text) # html tags | |
| text = ''.join([c for c in text if c not in string.punctuation])# Remove punctuation | |
| text = ' '.join([word for word in text.split() if word not in stop_words]) | |
| text = [word for word in text.split() if not word.isdigit()] | |
| text = ' '.join(text) | |
| return text | |
| # Функция для предсказания класса отзыва | |
| def classify_review_tf(review): | |
| # Векторизация отзыва | |
| review_vector = vectorizer_tf.transform([review]) | |
| # Предсказание | |
| start_time = time.time() | |
| prediction = model_tf.predict(review_vector) | |
| end_time = time.time() | |
| # Время предсказания | |
| prediction_time = end_time - start_time | |
| return prediction[0], prediction_time | |
| VOCAB_SIZE = len(vocab_to_int) + 1 # add 1 for the padding token | |
| EMBEDDING_DIM = 32 | |
| HIDDEN_SIZE = 32 | |
| SEQ_LEN = 100 | |
| class BahdanauAttention(nn.Module): | |
| def __init__(self, hidden_size: torch.Tensor = HIDDEN_SIZE) -> None: | |
| super().__init__() | |
| self.W_q = nn.Linear(hidden_size, hidden_size) | |
| self.W_k = nn.Linear(hidden_size, hidden_size) | |
| self.V = nn.Linear(HIDDEN_SIZE, 1) | |
| def forward( | |
| self, | |
| keys: torch.Tensor, | |
| query: torch.Tensor | |
| ) -> Tuple[torch.Tensor, torch.Tensor]: | |
| query = self.W_q(query) | |
| keys = self.W_k(keys) | |
| energy = self.V(torch.tanh(query.unsqueeze(1) + keys)).squeeze(-1) | |
| weights = F.softmax(energy, -1) | |
| context = torch.bmm(weights.unsqueeze(1), keys) | |
| return context, weights | |
| embedding_matrix = np.zeros((VOCAB_SIZE, EMBEDDING_DIM)) | |
| embedding_layer = torch.nn.Embedding.from_pretrained(torch.FloatTensor(embedding_matrix)) | |
| class LSTMConcatAttention(nn.Module): | |
| def __init__(self) -> None: | |
| super().__init__() | |
| # self.embedding = nn.Embedding(VOCAB_SIZE, EMBEDDING_DIM) | |
| self.embedding = embedding_layer | |
| self.lstm = nn.LSTM(EMBEDDING_DIM, HIDDEN_SIZE, batch_first=True) | |
| self.attn = BahdanauAttention(HIDDEN_SIZE) | |
| self.clf = nn.Sequential( | |
| nn.Linear(HIDDEN_SIZE, 128), | |
| nn.Dropout(), | |
| nn.Tanh(), | |
| nn.Linear(128, 1) | |
| ) | |
| def forward(self, x): | |
| embeddings = self.embedding(x) | |
| outputs, (h_n, _) = self.lstm(embeddings) | |
| att_hidden, att_weights = self.attn(outputs, h_n.squeeze(0)) | |
| out = self.clf(att_hidden) | |
| return out, att_weights | |
| model_lstm = LSTMConcatAttention() # Инициализируйте с теми же параметрами, что использовались при обучении | |
| model_lstm.load_state_dict(torch.load("lstm/lstm_model.pth")) | |
| model_lstm.eval() | |
| # Проверка и добавление токена <UNK>, если он отсутствует | |
| if '<UNK>' not in vocab_to_int: | |
| vocab_to_int['<UNK>'] = len(vocab_to_int) # Присвоение нового уникального индекса | |
| # Проверка и добавление токена <PAD>, если он отсутствует | |
| if '<PAD>' not in vocab_to_int: | |
| vocab_to_int['<PAD>'] = len(vocab_to_int) # Присвоение нового уникального индекса | |
| def text_to_vector(text, unknown_token_id=0): | |
| words = text.split() | |
| vector = [vocab_to_int.get(word, unknown_token_id) for word in words] # здесь unknown_token_id - это ID для "неизвестных" слов | |
| return np.array(vector, dtype=np.int64) # Убедитесь, что тип данных int64 | |
| def classify_review_lstm(review: str, SEQ_LEN: int, model: nn.Module, threshold: float = 0.5): | |
| """Predict sentiment class for a review | |
| Args: | |
| review (str): Review text | |
| SEQ_LEN (int): sequence length | |
| model (nn.Module): trained model | |
| threshold (float): threshold for class prediction | |
| Returns: | |
| str: Predicted sentiment ('positive' or 'negative') | |
| """ | |
| inp = text_to_vector(review) | |
| inp_tensor = torch.tensor(inp, dtype=torch.int64) | |
| start_time = time.time() | |
| with torch.inference_mode(): | |
| pred, _ = model(inp_tensor.long().unsqueeze(0)) | |
| end_time = time.time() | |
| prediction_time = end_time - start_time | |
| # Convert prediction to sentiment label | |
| sentiment = 'positive' if pred.sigmoid().item() > threshold else 'negative' | |
| return sentiment, prediction_time | |
| tokenizer_rubert = AutoTokenizer.from_pretrained("cointegrated/rubert-tiny2") | |
| model_rubert = AutoModel.from_pretrained("cointegrated/rubert-tiny2") | |
| clf_rubert = LogisticRegression(max_iter=1000) # Предполагается, что ваша модель уже обучена | |
| with open('rubert/logistic_regression_model.pkl', 'rb') as f: | |
| clf_rubert = pickle.load(f) | |
| # Функция для предсказания | |
| def make_prediction(text): | |
| start_time = time.time() | |
| encoded = tokenizer_rubert(text, add_special_tokens=True, max_length=128, padding='max_length', truncation=True, return_tensors="pt") | |
| with torch.no_grad(): | |
| outputs = model_rubert(**encoded) | |
| features = outputs.last_hidden_state[:, 0, :].numpy() | |
| prediction = clf_rubert.predict(features) | |
| end_time = time.time() | |
| prediction_time = end_time - start_time | |
| return prediction[0], prediction_time | |
| # Создание интерфейса Streamlit | |
| st.title('Классификатор отзывов на клиники') | |
| # Текстовое поле для ввода отзыва | |
| user_review = st.text_input('Введите ваш отзыв на клинику') | |
| if st.button('Классифицировать'): | |
| if user_review: | |
| # Классификация отзыва | |
| prediction_tf, pred_time_tf = classify_review_tf(user_review) | |
| st.write(f'Предсказанный класс TF-IDF: {prediction_tf}') | |
| st.write(f'Время предсказания TF-IDF: {pred_time_tf:.4f} секунд') | |
| prediction_lstm, pred_time_lstm = classify_review_lstm(user_review, SEQ_LEN=SEQ_LEN, model=model_lstm) | |
| st.write(f'Предсказанный класс LSTM: {prediction_lstm}') | |
| st.write(f'Время предсказания LSTM: {pred_time_lstm:.4f} секунд') | |
| prediction_rubert, pred_time_rubert = make_prediction(user_review) | |
| prediction_ru = 'negative' if prediction_rubert == 0 else 'positive' | |
| st.write(f'Предсказанный класс RuBERT: {prediction_ru}') | |
| st.write(f'Время предсказания RuBERT: {pred_time_rubert:.4f} секунд') | |
| else: | |
| st.write('Пожалуйста, введите отзыв') | |
| if page == "Зоопарк моделей и F1-score": | |
| # Создание данных для таблицы | |
| data = { | |
| "Название модели": ["TF-IDF", "LSTM", "RuBert tiny-2"], | |
| "F-1 macro score": ["0,94", "0,89", "0,90"] | |
| } | |
| # Создание DataFrame | |
| df = pd.DataFrame(data) | |
| # Отображение таблицы в Streamlit | |
| st.table(df) | |
| if page == "Определение токсичности": | |
| # Функция для загрузки обученной модели | |
| def load_model(model_path): | |
| with open(model_path, 'rb') as file: | |
| model = pickle.load(file) | |
| return model | |
| # Загрузка обученной модели | |
| clf_c = load_model('toxic/logistic_regression_model_toxic.pkl') # Укажите путь к файлу модели | |
| # Загрузка токенизатора и модели BERT | |
| tokenizer_c = AutoTokenizer.from_pretrained("cointegrated/rubert-tiny-toxicity") | |
| model_c = AutoModel.from_pretrained("cointegrated/rubert-tiny-toxicity") | |
| # Функция для предсказания токсичности сообщения | |
| def predict_toxicity(text): | |
| encoded = tokenizer_c(text, return_tensors="pt", padding=True, truncation=True, max_length=512) | |
| with torch.no_grad(): | |
| outputs = model_c(**encoded) | |
| features = outputs.last_hidden_state[:, 0, :].numpy() | |
| prediction = clf_c.predict_proba(features) | |
| return prediction[0] | |
| model_checkpoint = 'cointegrated/rubert-tiny-toxicity' | |
| tokenizer_b = AutoTokenizer.from_pretrained(model_checkpoint) | |
| model_b = AutoModelForSequenceClassification.from_pretrained(model_checkpoint) | |
| def text2toxicity(text): | |
| with torch.no_grad(): | |
| inputs = tokenizer_b(text, return_tensors='pt', truncation=True, padding=True) | |
| proba = torch.sigmoid(model_b(**inputs).logits).cpu().numpy() | |
| return proba[0][1] | |
| # Создание интерфейса Streamlit | |
| st.title("Оценка токсичности сообщения") | |
| # Текстовое поле для ввода сообщения | |
| user_input = st.text_area("Введите сообщение для оценки") | |
| if st.button("Оценить токсичность сообщения кастомизированной моделью"): | |
| if user_input: | |
| # Оценка токсичности сообщения | |
| prediction = predict_toxicity(user_input)[1] | |
| st.write(f'Вероятность токсичности согласно кастомизированной модели: {prediction:.4f}') | |
| else: | |
| st.write("Пожалуйста, введите сообщение") | |
| if st.button('Определить токсичность базовой моделью'): | |
| if user_input: | |
| # Определение токсичности сообщения | |
| proba_toxicity = text2toxicity(user_input) | |
| st.write(f'Вероятность токсичности rubert-tiny-toxicity.pretrained: {proba_toxicity:.4f}') | |
| else: | |
| st.write('Пожалуйста, введите сообщение') | |
| if page == "Генерация текста": | |
| # Путь к вашим весам модели | |
| model_weights_path = 'gpt-2/model.pt' | |
| # Загружаем токенизатор от GPT-2 | |
| tokenizer = GPT2Tokenizer.from_pretrained("sberbank-ai/rugpt3small_based_on_gpt2") | |
| # Создаем экземпляр модели с архитектурой GPT-2, но без предварительно обученных весов | |
| model = GPT2LMHeadModel.from_pretrained('sberbank-ai/rugpt3small_based_on_gpt2') | |
| # Загружаем веса вашей модели | |
| model.load_state_dict(torch.load(model_weights_path, map_location='cpu')) | |
| # Переносим модель на устройство (GPU или CPU) | |
| device = 'cpu' | |
| model.to(device) | |
| model.eval() | |
| def main(): | |
| st.title("Генератор плохих отзывов больниц от ruGPT3") | |
| # Ввод текста от пользователя | |
| user_prompt = st.text_area("Введите текст-промпт:", "Я была в этой клинике") | |
| # Виджеты для динамической регуляции параметров | |
| max_length = st.slider("Выберите max_length:", 10, 300, 100) | |
| temperature = st.slider("Выберите temperature:", 1.0, 10.0, step=0.2) | |
| top_k = st.slider("Выберите top_k:", 100, 500, 50) | |
| top_p = st.slider("Выберите top_p:", 0.1, 1.0, 0.95, step=0.05) | |
| num_beams = st.slider('Выберите num_beams:', 5, 40, step=1) | |
| # Генерация текста при нажатии на кнопку | |
| if st.button("Сгенерировать текст"): | |
| with torch.no_grad(): | |
| prompt = tokenizer.encode(user_prompt, return_tensors='pt').to(device) | |
| out = model.generate( | |
| input_ids=prompt, | |
| max_length=max_length, | |
| num_beams=num_beams, | |
| temperature=temperature, | |
| top_k=top_k, | |
| top_p=top_p, | |
| no_repeat_ngram_size=2, | |
| ).cpu().numpy() | |
| generated_text = tokenizer.decode(out[0], skip_special_tokens=True) | |
| st.subheader("Сгенерированный текст:") | |
| st.write(generated_text) | |
| if __name__ == "__main__": | |
| main() | |