Solar-Iz commited on
Commit
b53579a
1 Parent(s): 8a0fa03

Upload 9 files

Browse files
app.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import streamlit as st
4
+ import pickle
5
+ import time
6
+ from typing import Tuple
7
+ from sklearn.feature_extraction.text import TfidfVectorizer
8
+ import transformers
9
+ import numpy as np
10
+ from sklearn.model_selection import train_test_split
11
+ from sklearn.linear_model import LogisticRegression
12
+ from sklearn.metrics import f1_score
13
+ import torch
14
+ from transformers import AutoTokenizer, AutoModel
15
+ from torch.utils.data import TensorDataset, DataLoader
16
+ from sklearn.preprocessing import LabelEncoder
17
+ import re
18
+ import string
19
+ import numpy as np
20
+ import torch.nn as nn
21
+ import json
22
+ import gensim
23
+ import torch.nn.functional as F
24
+ from transformers import GPT2LMHeadModel, GPT2Tokenizer
25
+ from transformers import AutoModelForSequenceClassification
26
+
27
+
28
+
29
+ st.title('10-я неделя DS. Классификация отзывов, определение токсичности и генерация текста')
30
+
31
+ st.sidebar.header('Выберите страницу')
32
+ page = st.sidebar.radio("Выберите страницу", ["Вводная информация", "Классификация отзывов", "Зоопарк моделей и F1-score", "Определение токсичности", "Генерация текста"])
33
+
34
+ if page == "Вводная информация":
35
+
36
+ st.subheader('*Задача №1*: Классификация отзывов на медицинские учреждения')
37
+ st.write('Задача в двух словах: необходимо дать классификацию отзыва тремя моделями, время, за которое происходит классификаци отзыва, а также таблицу сравнения моделей по F-1 macro для моделей')
38
+
39
+ st.subheader('*Задача №2*: Определение токсичности')
40
+ st.write('Задача в двух словах: Оценка степени токсичности пользовательского сообщения ')
41
+
42
+ st.subheader('*Задача №3*: Генерация текста')
43
+ st.write('Задача в двух словах: Генерация текста GPT-моделью по пользовательскому prompt')
44
+
45
+ st.subheader('☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️☀️')
46
+
47
+ st.subheader('Выполнила команда "BERT": Алексей А., Светлана, Алиса')
48
+
49
+
50
+ if page == "Классификация отзывов":
51
+ # Загрузка tf-idf модели и векторайзера
52
+ with open('tf-idf/tf-idf.pkl', 'rb') as f:
53
+ model_tf = pickle.load(f)
54
+
55
+ with open('tf-idf/tf-idf_vectorizer.pkl', 'rb') as f:
56
+ vectorizer_tf = pickle.load(f)
57
+
58
+ # Загрузка словаря vocab_to_int и Word2Vec модели
59
+ with open('lstm/vocab_to_int.json', 'r') as f:
60
+ vocab_to_int = json.load(f)
61
+
62
+ word2vec_model = gensim.models.Word2Vec.load("lstm/word2vec.model")
63
+
64
+ stop_words = ['и', 'в', 'во', 'не', 'что', 'он', 'на', 'я', 'с', 'со', 'как', 'а', 'то', 'все', 'она', 'так', 'его', 'но', 'да', 'ты', 'к', 'у', 'же', 'вы', 'за', 'бы', 'по', 'только', 'ее', 'мне', 'было', 'вот', 'от', 'меня', 'еще', 'нет', 'о', 'из', 'ему', 'теперь', 'когда', 'даже', 'ну', 'вдруг', 'ли', 'если', 'уже', 'или', 'ни', 'быть', 'был', 'него', 'до', 'вас', 'нибудь', 'опять', 'уж', 'вам', 'ведь', 'там', 'потом', 'себя', 'ничего', 'ей', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней', 'для', 'мы', 'тебя', 'их', 'чем', 'была', 'сам', 'чтоб', 'без', 'будто', 'чего', 'раз', 'тоже', 'себе', 'под', 'будет', 'ж', 'тогда', 'кто', 'этот', 'того', 'потому', 'этого', 'какой', 'совсем', 'ним', 'здесь', 'этом', 'один', 'почти', 'мой', 'тем', 'чтобы', 'нее', 'сейчас', 'были', 'куда', 'зачем', 'всех', 'никогда', 'можно', 'при', 'наконец', 'два', 'об', 'другой', 'хоть', 'после', 'над', 'больше', 'тот', 'через', 'эти', 'нас', 'про', 'всего', 'них', 'какая', 'много', 'разве', 'три', 'эту', 'моя', 'впрочем', 'хорошо', 'свою', 'этой', 'перед', 'иногда', 'лучше', 'чуть', 'том', 'нельзя', 'такой', 'им', 'более', 'всегда', 'конечно', 'всю', 'между']
65
+
66
+ def data_preprocessing(text: str) -> str:
67
+ text = text.lower()
68
+ text = re.sub('<.*?>', '', text) # html tags
69
+ text = ''.join([c for c in text if c not in string.punctuation])# Remove punctuation
70
+ text = ' '.join([word for word in text.split() if word not in stop_words])
71
+ text = [word for word in text.split() if not word.isdigit()]
72
+ text = ' '.join(text)
73
+ return text
74
+
75
+ # Функция для предсказания класса отзыва
76
+ def classify_review_tf(review):
77
+ # Векторизация отзыва
78
+ review_vector = vectorizer_tf.transform([review])
79
+ # Предсказание
80
+ start_time = time.time()
81
+ prediction = model_tf.predict(review_vector)
82
+ end_time = time.time()
83
+ # Время предсказания
84
+ prediction_time = end_time - start_time
85
+ return prediction[0], prediction_time
86
+
87
+ VOCAB_SIZE = len(vocab_to_int) + 1 # add 1 for the padding token
88
+ EMBEDDING_DIM = 32
89
+ HIDDEN_SIZE = 32
90
+ SEQ_LEN = 100
91
+
92
+ class BahdanauAttention(nn.Module):
93
+ def __init__(self, hidden_size: torch.Tensor = HIDDEN_SIZE) -> None:
94
+ super().__init__()
95
+
96
+ self.W_q = nn.Linear(hidden_size, hidden_size)
97
+ self.W_k = nn.Linear(hidden_size, hidden_size)
98
+ self.V = nn.Linear(HIDDEN_SIZE, 1)
99
+
100
+ def forward(
101
+ self,
102
+ keys: torch.Tensor,
103
+ query: torch.Tensor
104
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
105
+ query = self.W_q(query)
106
+ keys = self.W_k(keys)
107
+
108
+ energy = self.V(torch.tanh(query.unsqueeze(1) + keys)).squeeze(-1)
109
+ weights = F.softmax(energy, -1)
110
+ context = torch.bmm(weights.unsqueeze(1), keys)
111
+ return context, weights
112
+
113
+ embedding_matrix = np.zeros((VOCAB_SIZE, EMBEDDING_DIM))
114
+ embedding_layer = torch.nn.Embedding.from_pretrained(torch.FloatTensor(embedding_matrix))
115
+
116
+ class LSTMConcatAttention(nn.Module):
117
+ def __init__(self) -> None:
118
+ super().__init__()
119
+
120
+ # self.embedding = nn.Embedding(VOCAB_SIZE, EMBEDDING_DIM)
121
+ self.embedding = embedding_layer
122
+ self.lstm = nn.LSTM(EMBEDDING_DIM, HIDDEN_SIZE, batch_first=True)
123
+ self.attn = BahdanauAttention(HIDDEN_SIZE)
124
+ self.clf = nn.Sequential(
125
+ nn.Linear(HIDDEN_SIZE, 128),
126
+ nn.Dropout(),
127
+ nn.Tanh(),
128
+ nn.Linear(128, 1)
129
+ )
130
+
131
+ def forward(self, x):
132
+ embeddings = self.embedding(x)
133
+ outputs, (h_n, _) = self.lstm(embeddings)
134
+ att_hidden, att_weights = self.attn(outputs, h_n.squeeze(0))
135
+ out = self.clf(att_hidden)
136
+ return out, att_weights
137
+
138
+ model_lstm = LSTMConcatAttention() # Инициализируйте с теми же параметрами, что использовались при обучении
139
+ model_lstm.load_state_dict(torch.load("lstm/lstm_model.pth"))
140
+ model_lstm.eval()
141
+
142
+ # Проверка и добавление токена <UNK>, если он отсутствует
143
+ if '<UNK>' not in vocab_to_int:
144
+ vocab_to_int['<UNK>'] = len(vocab_to_int) # Присвоение нового уникального индекса
145
+
146
+ # Проверка и добавление токена <PAD>, если он отсутствует
147
+ if '<PAD>' not in vocab_to_int:
148
+ vocab_to_int['<PAD>'] = len(vocab_to_int) # Присвоение нового уникального индекса
149
+
150
+ def text_to_vector(text, unknown_token_id=0):
151
+ words = text.split()
152
+ vector = [vocab_to_int.get(word, unknown_token_id) for word in words] # здесь unknown_token_id - это ID для "неизвестных" слов
153
+ return np.array(vector, dtype=np.int64) # Убедитесь, что тип данных int64
154
+
155
+
156
+ def classify_review_lstm(review: str, SEQ_LEN: int, model: nn.Module, threshold: float = 0.5):
157
+ """Predict sentiment class for a review
158
+
159
+ Args:
160
+ review (str): Review text
161
+ SEQ_LEN (int): sequence length
162
+ model (nn.Module): trained model
163
+ threshold (float): threshold for class prediction
164
+
165
+ Returns:
166
+ str: Predicted sentiment ('positive' or 'negative')
167
+ """
168
+ inp = text_to_vector(review)
169
+ inp_tensor = torch.tensor(inp, dtype=torch.int64)
170
+ start_time = time.time()
171
+ with torch.inference_mode():
172
+ pred, _ = model(inp_tensor.long().unsqueeze(0))
173
+ end_time = time.time()
174
+ prediction_time = end_time - start_time
175
+ # Convert prediction to sentiment label
176
+ sentiment = 'positive' if pred.sigmoid().item() > threshold else 'negative'
177
+
178
+ return sentiment, prediction_time
179
+
180
+ tokenizer_rubert = AutoTokenizer.from_pretrained("cointegrated/rubert-tiny2")
181
+ model_rubert = AutoModel.from_pretrained("cointegrated/rubert-tiny2")
182
+ clf_rubert = LogisticRegression(max_iter=1000) # Предполагается, что ваша модель уже обучена
183
+
184
+ with open('rubert/logistic_regression_model.pkl', 'rb') as f:
185
+ clf_rubert = pickle.load(f)
186
+
187
+ # Функция для предсказания
188
+ def make_prediction(text):
189
+ start_time = time.time()
190
+ encoded = tokenizer_rubert(text, add_special_tokens=True, max_length=128, padding='max_length', truncation=True, return_tensors="pt")
191
+ with torch.no_grad():
192
+ outputs = model_rubert(**encoded)
193
+ features = outputs.last_hidden_state[:, 0, :].numpy()
194
+ prediction = clf_rubert.predict(features)
195
+ end_time = time.time()
196
+ prediction_time = end_time - start_time
197
+ return prediction[0], prediction_time
198
+
199
+ # Создание интерфейса Streamlit
200
+ st.title('Классификатор отзывов на клиники')
201
+
202
+ # Текстовое поле для ввода отзыва
203
+ user_review = st.text_input('Введите ваш отзыв на клинику')
204
+
205
+ if st.button('Классифицировать'):
206
+ if user_review:
207
+ # Классификация отзыва
208
+ prediction_tf, pred_time_tf = classify_review_tf(user_review)
209
+ st.write(f'Предсказанный класс TF-IDF: {prediction_tf}')
210
+ st.write(f'Время предсказания TF-IDF: {pred_time_tf:.4f} секунд')
211
+ prediction_lstm, pred_time_lstm = classify_review_lstm(user_review, SEQ_LEN=SEQ_LEN, model=model_lstm)
212
+ st.write(f'Предсказанный класс LSTM: {prediction_lstm}')
213
+ st.write(f'Время предсказания LSTM: {pred_time_lstm:.4f} секунд')
214
+ prediction_rubert, pred_time_rubert = make_prediction(user_review)
215
+ prediction_ru = 'negative' if prediction_rubert == 0 else 'positive'
216
+ st.write(f'Предсказанный класс RuBERT: {prediction_ru}')
217
+ st.write(f'Время предсказания RuBERT: {pred_time_rubert:.4f} секунд')
218
+ else:
219
+ st.write('Пожалуйста, введите отзыв')
220
+
221
+ if page == "Зоопарк моделей и F1-score":
222
+ # Создание данных для таблицы
223
+ data = {
224
+ "Название модели": ["TF-IDF", "LSTM", "RuBert tiny-2"],
225
+ "F-1 macro score": ["0,94", "0,89", "0,90"]
226
+ }
227
+
228
+ # Создание DataFrame
229
+ df = pd.DataFrame(data)
230
+
231
+ # Отображение таблицы в Streamlit
232
+ st.table(df)
233
+
234
+
235
+ if page == "Определение токсичности":
236
+
237
+ # Функция для загрузки обученной модели
238
+ def load_model(model_path):
239
+ with open(model_path, 'rb') as file:
240
+ model = pickle.load(file)
241
+ return model
242
+
243
+ # Загрузка обученной модели
244
+ clf_c = load_model('toxic/logistic_regression_model_toxic.pkl') # Укажите путь к файлу модели
245
+
246
+ # Загрузка токенизатора и модели BERT
247
+ tokenizer_c = AutoTokenizer.from_pretrained("cointegrated/rubert-tiny-toxicity")
248
+ model_c = AutoModel.from_pretrained("cointegrated/rubert-tiny-toxicity")
249
+
250
+ # Функция для предсказания токсичности сообщения
251
+ def predict_toxicity(text):
252
+ encoded = tokenizer_c(text, return_tensors="pt", padding=True, truncation=True, max_length=512)
253
+ with torch.no_grad():
254
+ outputs = model_c(**encoded)
255
+ features = outputs.last_hidden_state[:, 0, :].numpy()
256
+ prediction = clf_c.predict_proba(features)
257
+ return prediction[0]
258
+
259
+ model_checkpoint = 'cointegrated/rubert-tiny-toxicity'
260
+ tokenizer_b = AutoTokenizer.from_pretrained(model_checkpoint)
261
+ model_b = AutoModelForSequenceClassification.from_pretrained(model_checkpoint)
262
+
263
+ def text2toxicity(text):
264
+ with torch.no_grad():
265
+ inputs = tokenizer_b(text, return_tensors='pt', truncation=True, padding=True)
266
+ proba = torch.sigmoid(model_b(**inputs).logits).cpu().numpy()
267
+ return proba[0][1]
268
+
269
+ # Создание интерфейса Streamlit
270
+ st.title("Оценка токсичности сообщения")
271
+
272
+ # Текстовое поле для ввода сообщения
273
+ user_input = st.text_area("Введите сообщение для оценки")
274
+
275
+ if st.button("Оценить токсичность сообщения кастомизированной моделью"):
276
+ if user_input:
277
+ # Оценка токсичности сообщения
278
+ prediction = predict_toxicity(user_input)[1]
279
+ st.write(f'Вероятность токсичности согласно кастомизированной модели: {prediction:.4f}')
280
+ else:
281
+ st.write("Пожалуйста, введите сообщение")
282
+
283
+ if st.button('Определить токсичность базовой моделью'):
284
+ if user_input:
285
+ # Определение токсичности сообщения
286
+ proba_toxicity = text2toxicity(user_input)
287
+ st.write(f'Вероятность токсичности rubert-tiny-toxicity.pretrained: {proba_toxicity:.4f}')
288
+ else:
289
+ st.write('Пожалуйста, введите сообщение')
290
+
291
+
292
+
293
+ if page == "Генерация текста":
294
+
295
+ # Путь к вашим весам модели
296
+ model_weights_path = 'gpt-2/model.pt'
297
+
298
+ # Загружаем токенизатор от GPT-2
299
+ tokenizer = GPT2Tokenizer.from_pretrained("sberbank-ai/rugpt3small_based_on_gpt2")
300
+
301
+ # Создаем экземпляр модели с архитектурой GPT-2, но без предварительно обученных весов
302
+ model = GPT2LMHeadModel.from_pretrained('sberbank-ai/rugpt3small_based_on_gpt2')
303
+
304
+ # Загружаем веса вашей модели
305
+ model.load_state_dict(torch.load(model_weights_path, map_location='cpu'))
306
+
307
+ # Переносим модель на устройство (GPU или CPU)
308
+ device = 'cpu'
309
+ model.to(device)
310
+ model.eval()
311
+
312
+ def main():
313
+ st.title("Генератор плохих отзывов больниц от ruGPT3")
314
+
315
+ # Ввод текста от пользователя
316
+ user_prompt = st.text_area("Введите текст-промпт:", "Я была в этой клинике")
317
+
318
+ # Виджеты для динамической регуляции параметров
319
+ max_length = st.slider("Выберите max_length:", 10, 300, 100)
320
+ temperature = st.slider("Выберите temperature:", 1.0, 10.0, step=0.2)
321
+ top_k = st.slider("Выберите top_k:", 100, 500, 50)
322
+ top_p = st.slider("Выберите top_p:", 0.1, 1.0, 0.95, step=0.05)
323
+ num_beams = st.slider('Выберите num_beams:', 5, 40, step=1)
324
+
325
+ # Генерация текста при нажатии на кнопку
326
+ if st.button("Сгенерировать текст"):
327
+ with torch.no_grad():
328
+ prompt = tokenizer.encode(user_prompt, return_tensors='pt').to(device)
329
+ out = model.generate(
330
+ input_ids=prompt,
331
+ max_length=max_length,
332
+ num_beams=num_beams,
333
+ temperature=temperature,
334
+ top_k=top_k,
335
+ top_p=top_p,
336
+ no_repeat_ngram_size=2,
337
+ ).cpu().numpy()
338
+ generated_text = tokenizer.decode(out[0], skip_special_tokens=True)
339
+ st.subheader("Сгенерированный текст:")
340
+ st.write(generated_text)
341
+
342
+ if __name__ == "__main__":
343
+ main()
344
+
lstm/lstm_model.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6fd3a156141324e2c9eb10ac3458a0e74ebb9c49aef162c5794a415f91de81f
3
+ size 11341922
lstm/rnn_preprocessing.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import string
3
+ import numpy as np
4
+ import torch
5
+
6
+ from nltk.corpus import stopwords
7
+ stop_words = set(stopwords.words('english'))
8
+
9
+ def data_preprocessing(text: str) -> str:
10
+ """preprocessing string: lowercase, removing html-tags, punctuation,
11
+ stopwords, digits
12
+
13
+ Args:
14
+ text (str): input string for preprocessing
15
+
16
+ Returns:
17
+ str: preprocessed string
18
+ """
19
+
20
+ text = text.lower()
21
+ text = re.sub('<.*?>', '', text) # html tags
22
+ text = ''.join([c for c in text if c not in string.punctuation])# Remove punctuation
23
+ text = ' '.join([word for word in text.split() if word not in stop_words])
24
+ text = [word for word in text.split() if not word.isdigit()]
25
+ text = ' '.join(text)
26
+ return text
27
+
28
+ def get_words_by_freq(sorted_words: list, n: int = 10) -> list:
29
+ return list(filter(lambda x: x[1] > n, sorted_words))
30
+
31
+ def padding(review_int: list, seq_len: int) -> np.array: # type: ignore
32
+ """Make left-sided padding for input list of tokens
33
+
34
+ Args:
35
+ review_int (list): input list of tokens
36
+ 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
37
+
38
+ Returns:
39
+ np.array: padded sequences
40
+ """
41
+ features = np.zeros((len(review_int), seq_len), dtype = int)
42
+ for i, review in enumerate(review_int):
43
+ if len(review) <= seq_len:
44
+ zeros = list(np.zeros(seq_len - len(review)))
45
+ new = zeros + review
46
+ else:
47
+ new = review[: seq_len]
48
+ features[i, :] = np.array(new)
49
+
50
+ return features
51
+
52
+ def preprocess_single_string(
53
+ input_string: str,
54
+ seq_len: int,
55
+ vocab_to_int: dict,
56
+ verbose : bool = False
57
+ ) -> torch.tensor:
58
+ """Function for all preprocessing steps on a single string
59
+
60
+ Args:
61
+ input_string (str): input single string for preprocessing
62
+ 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
63
+ vocab_to_int (dict, optional): word corpus {'word' : int index}. Defaults to vocab_to_int.
64
+
65
+ Returns:
66
+ list: preprocessed string
67
+ """
68
+
69
+ preprocessed_string = data_preprocessing(input_string)
70
+ result_list = []
71
+ for word in preprocessed_string.split():
72
+ try:
73
+ result_list.append(vocab_to_int[word])
74
+ except KeyError as e:
75
+ if verbose:
76
+ print(f'{e}: not in dictionary!')
77
+ pass
78
+ result_padded = padding([result_list], seq_len)[0]
79
+
80
+ return torch.tensor(result_padded)
lstm/vocab_to_int.json ADDED
The diff for this file is too large to render. See raw diff
 
lstm/word2vec.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6026f577c772a215706fdc1afa07bdbf069b30dc9f65b658bc638c52d6d79611
3
+ size 1251312
rubert/logistic_regression_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3a7080b96e67f49e95633afb9f73f8df4c42859da5c72777cd4e5fb5c21373b3
3
+ size 3210
tf-idf/tf-idf.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:26ac8a2985942f283db82f07dbe2124b18e50d05c0f1e98ede95338a26911b42
3
+ size 529407
tf-idf/tf-idf_vectorizer.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:772dfeb1b7264ebf743229968e7d272f5aef1eb24911672708a485dc0421f147
3
+ size 2667929
toxic/logistic_regression_model_toxic.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0a7214a8bbc6c4fde231a013fe2808d94532d6a84f054740cf6e897e86e9cd6b
3
+ size 3176