Цель этой статьи — пометить конфиденциальные комментарии, постоянно присутствующие на нескольких платформах социальных сетей, таких как Youtube, Linkedin и т. д., с помощью BERT и преобразователей предложений.
Одним из насущных вопросов при создании такой модели является время, необходимое для предоставления результатов. Средняя модель занимает около 1 или 2 секунд, когда она развернута с хорошо обслуживаемым сервером, состоящим из графических процессоров. Наоборот, то же самое время увеличивается экспоненциально, если вся модель основана на процессоре.
Мой подход к этой проблеме заключается в том, что мы можем сохранить наши кодировки в файле pickle, размер которого зависит от набора данных (для этой статьи размер составлял ~50 МБ для 16 000 предложений), а затем выполнить проверку на сходство. Без дальнейших ожиданий, давайте погрузимся в раздел кода.
Загрузка и настройка данных
Чтобы продолжить, набор данных доступен здесь (данные не принадлежат мне, и это чисто собственность kaggle)
После распаковки основное внимание уделяется файлу с именем «train.csv».
# !pip install scipy # !pip install pandas # !pip install sentence-transformers import scipy import pandas as pd import pickle import re import string from sentence_transformers import SentenceTransformer #some of the packages we will be utilizing
Давайте прочитаем и интерпретируем, как данные представлены в настоящее время.
df = pd.read_csv('./train.csv') df.sample(5)
Следующий код выдаст таблицу, состоящую из разных комментариев и их соответствующих жанров.
Как мы видим, существует пять классов для маркировки интенсивности комментария. Кроме того, мы также можем заметить, что данные находятся в очень необработанном формате, и поэтому нам необходимо очистить их перед подачей в кодировщик BERT.
Предварительная обработка данных
Во-первых, нам нужны только строки, содержащие токсичные тексты, поэтому мы пишем
df = (df[(df['toxic']==1) | (df['severe_toxic']==1) | (df['obscene']==1) | (df['threat']==1) | \ (df['insult']==1) | (df['identity_hate']==1)]) df.shape #(16225, 8)
Следующий фрагмент удалит все строки, в которых комментарии чистые, так как мы хотим, чтобы наши данные были сосредоточены именно на отрицательных частях.
После этого наша следующая цель — очистить данные, которые содержат МНОГО ошибок и мусорных символов.
import re import string def clean_text(text): text = text.lower() text = re.sub(r"i'm", "i am", text) text = re.sub(r"\r", "", text) text = re.sub(r"he's", "he is", text) text = re.sub(r"she's", "she is", text) text = re.sub(r"it's", "it is", text) text = re.sub(r"that's", "that is", text) text = re.sub(r"what's", "that is", text) text = re.sub(r"where's", "where is", text) text = re.sub(r"how's", "how is", text) text = re.sub(r"\'ll", " will", text) text = re.sub(r"\'ve", " have", text) text = re.sub(r"\'re", " are", text) text = re.sub(r"\'d", " would", text) text = re.sub(r"\'re", " are", text) text = re.sub(r"won't", "will not", text) text = re.sub(r"can't", "cannot", text) text = re.sub(r"n't", " not", text) text = re.sub(r"n'", "ng", text) text = re.sub(r"'bout", "about", text) text = re.sub(r"'til", "until", text) text = re.sub(r"[-()\"#/@;:<>{}`+=~|.!?,]", "", text) text = text.translate(str.maketrans('', '', string.punctuation)) text = re.sub("(\\W)"," ",text) text = re.sub('\S*\d\S*\s*','', text) return text df['comment_text'] = df['comment_text'].apply(clean_text)
Следующая функция поможет удалить такие символы и создать достойный кодирования набор данных. После обработки датафрейм выглядит примерно так:
Теперь нам нужно создать один столбец со значением 1 для всех таких комментариев и удалить все эти другие ненужные столбцы («токсичные», «серьезные_токсичные» и т. д.). анализ на него в будущем, они имеют привилегию сделать это. Для этого достаточно одной строки кода.
df['flag_toxic'] = 1 df.drop(['toxic', 'severe_toxic', 'obscene', 'threat', 'insult', 'identity_hate'], axis = 1, inplace=True)
Окончательно !! Наша предварительная обработка завершена, и теперь нам нужно создать экземпляр нашего преобразователя предложений BERT.
Кодирование и сохранение вложений
Используя преобразователи предложений, мы вызываем BERT, а затем кодируем наши предложения-запросы.
bert_based_embedder = SentenceTransformer('bert-base-nli-mean-tokens') input_sentences = df['comment_text'].tolist() input_sentence_embeddings = bert_based_embedder.encode(input_sentences)
Следующий код будет выполняться примерно 15–20 минут в зависимости от вычислительной мощности вашей машины. Как только это будет сделано, вы можете сохранить свои вложения, используя pickle в python, чтобы вы могли напрямую загружать их для прогнозов в будущем, например
with open('input_sentence_clean_embeddings.pickle', 'wb') as file: pickle.dump(query_embeddings, file) file.close()
Как только это будет сделано, вы также можете восстановить свои вложения, используя аналогичный код, просто заменив определенные компоненты.
with open('query_embeddings_clean.pickle', 'rb') as file: input_sentence_embeddings = pickle.load(file)
Вычисление подобия с использованием косинусного расстояния
Теперь, когда наше вложение готово, мы можем создать функцию, в которой мы берем входное предложение, кодируем его и вычисляем расстояние между нашим существующим вложением. Это можно сделать так
def check(comment): comment_embeddings = bert_based_embedder.encode(comment) distances = scipy.spatial.distance.cdist(input_sentence_embeddings, [comment_embeddings], "cosine")[0] print(1-distances) if(1-distances>=0.5): x = 'The above statement needs to be flagged' return x else: x = 'Nothing wrong here' return x
Я вычел значение расстояния из 1,0, чтобы получить четкую оценку оценки, поскольку косинусное сходство работает таким образом, что близость приводит к меньшему значению. Кроме того, мы можем настроить 0,5 в соответствии с нашими потребностями, более высокое значение означает, что утверждение/комментарий должны быть действительно токсичными или плохими для срабатывания, и наоборот.
Посмотрите здесь, если хотите узнать больше о косинусном подобии
value = check('It was a good day !') ''' Output : 'Nothing wrong here' [0.05024188] ''' value = check('Shut up you imbecile !') ''' Output : 'The above statement needs to be flagged' [0.62924553] ''' value = check('take your dumb @$$ away from here') Output : 'The above statement needs to be flagged' [0.55886211] '''
Плюсы: время получения результатов ближе к 200 мс (быстрее, чем у других моделей без поддержки графического процессора).
Минусы: может потребоваться больше данных для повышения точности
Спасибо !! за чтение моего первого блога, надеюсь, вам понравилось. Не стесняйтесь оставлять отзывы, и весь код для этого блога приведен ниже.