Spaces:
Runtime error
Runtime error
File size: 22,615 Bytes
22169da |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
import streamlit as st
import tools
st.title('Message moderation lab')
st.write(
"""
Термин «модерация» происходит от латинского «moderor», что значит «умерять, сдерживать».
Суть задачи модерации состоит в контроле за выполнением законов, правил, требований и ограничений в
любых сообществах и сервисах — будь то простое общение в социальных сетях или деловые переговоры на онлайн площадке.
Автоматические системы модерации внедряются в веб-сервисы и приложения, где необходимо обрабатывать большое
количество сообщений пользователей. Такие системы позволяют сократить издержки на ручную модерацию, ускорить её и
обрабатывать все сообщения пользователей в real-time.
Со временем пользователи подстраиваются и учатся обманывать такие системы, например пользователи:
- генерируют опечатки: you are stupit asswhol, fack u
- заменяют буквенные символы на цифры, похожие по описанию: n1gga, b0ll0cks,
- вставляют дополнительные пробелы: i d i o t,
- удаляют пробелы между словами: dieyoustupid
- указывают контактные данные: восем-906-три единицы-два раза по две единицы
и многое другое.
Для того, чтобы обучить классификатор устойчивый к таким подменам, нужно поступить так, как поступают пользователи:
сгенерировать такие же изменения в сообщениях и добавить их в обучающую выборку к основным данным.
В целом, эта борьба неизбежна: пользователи всегда будут пытаться находить уязвимости и хаки,
а модераторы реализовывать новые алгоритмы.
В примере ниже можно ознакомиться с работой разных алгоритмов по выявлению наличия контактных данных в сообщениях
пользователей. Это актуально в первую очередь для торговых площадок и других онлайн площадок по продаже и
рекомендации товаров и услуг. Актуально это потому, что пользователи не всегда желают платить комиссию за работу
сервиса и пытаются осуществлять сделки напрямую, минуя сервис.
В данном примере сообщения пользователей подвергаются проверке тремя алгоритмами по поиску контактных данных:
- регулярные выражения (regex)
- TF-IDF, на основе частотности слов
- нейросеть BERT
1. Регулярные выражения
Регулярные выражения представляют собой похожий, но гораздо более сильный инструмент для поиска строк, проверки их
на соответствие какому-либо шаблону и другой подобной работы. Англоязычное название этого
инструмента — Regular Expressions или просто RegExp.
"""
)
with st.expander(
label='Блок теории про регулярные выражения'
):
st.write(
"""
В самом общем смысле регулярные выражения — это последовательности символов для поиска соответствий шаблону.
Они являются экземплярами регулярного языка и широко применяются для парсинга текста или валидации входных строк.
Представьте лист картона, в котором вырезаны определенные фигуры. И только фигуры, точно соответствующие вырезам,
смогут через них пройти. В данном случае лист картона аналогичен строке регулярного выражения.
"""
)
st.image(
image='images/re.jpeg',
caption='Суть работы регулярных выражений',
use_column_width=True
)
st.write(
"""
Несколько случаев применения регулярных выражений:
- парсинг входных данных, например текста, логов, веб-информации и т.д.;
- валидация пользовательского ввода;
- тестирование результатов вывода;
- точный поиск текста;
- реструктуризация данных.
Регулярные выражения отлично подходят, когда есть четкий формат и структура данных. В нашем же случае пользователям
легко будет обмануть систему модерации сообщений, если она будет построена только на регулярных выражениях.
Нужно что-то посложнее.
"""
)
st.write(
"""
2. TF-IDF (TF — term frequency, IDF — inverse document frequency).
Мера TF-IDF является произведением двух сомножителей TF и IDF.
TF - частота слова - отношение числа вхождений некоторого слова к общему числу слов документа.
Таким образом, оценивается важность слова в пределах отдельного документа.
IDF - обратная частота документа - инверсия частоты, с которой некоторое слово встречается в документах коллекции.
Учёт IDF уменьшает вес широкоупотребительных слов. Для каждого уникального слова в пределах конкретной коллекции
документов существует только одно значение IDF.
"""
)
with st.expander(
label='Блок теории про TF-IDF'
):
st.image(
image='images/tf_idf_formula.jpg',
caption='Формула TF-IDF',
use_column_width=True
)
st.write(
"""
TF рассчитывается по следующей формуле:
"""
)
st.image(
image='images/tf_formula.jpg'
)
st.write(
"""
где t (от англ. term) — количество употребления слова, а n — общее число слов в тексте.
"""
)
st.image(
image='images/idf_formula.jpg'
)
st.write(
"""
где D - общее число текстов в корпусе, d - количество текстов, в которых это слово встречается.
IDF нужна в формуле, чтобы уменьшить вес слов, наиболее распространённых в любом другом тексте заданного корпуса.
"""
)
st.write(
"""
TF-IDF оценивает значимость слова в документе, на основе данных о всей коллекции документов. Данная мера
определяет вес слова за величину пропорциональную частоте его вхождения в документ и обратно пропорциональную
частоте его вхождения во всех документах коллекции.
Большая величина TF-IDF говорит об уникальности слова в тексте по отношению к корпусу.
Чем чаще оно встречается в конкретном тексте и реже в остальных, тем выше значение TF-IDF.
"""
)
st.write(
"""
3. Нейросеть BERT.
BERT — это нейронная сеть от Google, показавшая с большим отрывом state-of-the-art результаты на целом ряде задач.
С помощью BERT можно создавать программы с ИИ для обработки естественного языка: отвечать на вопросы, заданные
в произвольной форме, создавать чат-ботов, автоматические переводчики, анализировать текст и так далее.
"""
)
with st.expander(
label='Блок теории про BERT'
):
st.write(
"""
Чтобы подавать на вход нейронной сети текст, нужно его как-то представить в виде чисел. Проще всего это делать
побуквенно, подавая на каждый вход нейросети по одной букве. Тогда каждая буква будет кодироваться числом
от 0 до 32 (плюс какой-то запас на знаки препинания). Это так называемый character-level.
Но гораздо лучше результаты получаются, если мы предложения будем представлять не по одной букве, а подавая на
каждый вход нейросети сразу по целому слову (или хотя бы слогами). Это уже будет word-level. Самый простой
вариант — составить словарь со всеми существующими словами, и скармливать сети номер слова в этом словаре.
Например, если слово "собака" стоит в этом словаре на 1678 месте, то на вход нейросети для этого слова
подаем число 1678.
Вот только в естественном языке при слове "собака" у человека всплывает сразу множество
ассоциаций: "пушистая", "злая", "друг человека". Нельзя ли как-то закодировать эту особенность нашего мышления
в представлении для нейросети? Оказывается, можно. Для этого достаточно так пересортировать номера слов, чтобы
близкие по смыслу слова стояли рядом. Пусть будет, например, для "собака" число 1678, а для слова "пушистая"
число 1680. А для слова "чайник" число 9000. Как видите, цифры 1678 и 1680 находятся намного ближе друг к другу,
чем цифра 9000.
На практике, каждому слову назначают не одно число, а несколько — вектор, скажем, из 32 чисел. И расстояния
измеряют как расстояния между точками, на которые указывают эти вектора в пространстве соответствущей
размерности (для вектора длиной в 32 числа, это пространство с 32 размерностями, или с 32 осями).
Это позволяет сопоставлять одному слову сразу несколько близких по смыслу слов (смотря по какой оси считать).
Более того, с векторами можно производить арифметические операции. Классический пример: если из вектора,
обозначающего слово "король", вычесть вектор "мужчина" и прибавить вектор для слова "женщина", то получится
некий вектор-результат. И он чудесным образом будет соответствовать слову "королева". И действительно,
"король — мужчина + женщина = королева". Магия! И это не абстрактный пример, а
[реально так происходит](https://blog.acolyer.org/2016/04/21/the-amazing-power-of-word-vectors/). Учитывая,
что нейронные сети хорошо приспособлены для математических преобразований над своими входами, видимо это и
обеспечивает такую высокую эффективность этого метода.
Идея в основе BERT лежит очень простая: давайте на вход нейросети будем подавать фразы, в которых 15% слов
заменим на [MASK], и обучим нейронную сеть предсказывать эти закрытые маской слова.
Например, если подаем на вход нейросети фразу "Я пришел в [MASK] и купил [MASK]", она должна на выходе показать
слова "магазин" и "молоко". Это упрощенный пример с официальной страницы BERT, на более длинных предложениях
разброс возможных вариантов становится меньше, а ответ нейросети однозначнее.
А для того, чтобы нейросеть научилась понимать соотношения между разными предложениями, дополнительно обучим
ее предсказывать, является ли вторая фраза логичным продолжением первой. Или это какая-то случайная фраза, не
имеющая никакого отношения к первой.
Так, для двух предложений: "Я пошел в магазин." и "И купил там молоко.", нейросеть должна ответить,
что это логично. А если вторая фраза будет "Карась небо Плутон", то должна ответить, что это предложение никак
не связано с первым. Ниже мы поиграемся с обоими этими режимами работы BERT.
Обучив таким образом нейронную сеть на корпусе текстов из Wikipedia и сборнике книг BookCorpus
в течении 4 дней на 16 TPU, получили BERT.
"""
)
if st.checkbox('Сгенерировать рандомное сообщение'):
user_text = st.text_area(
label='Введите сообщение',
height=200,
value=tools.get_random_message(),
help='Попробуйте указать ссылки на vk, twich, twitter и др. каналы связи а также почту')
else:
user_text = st.text_area(
label='Введите сообщение',
height=200,
help='Попробуйте указать ссылки на vk, twich, twitter и др. каналы связи а также почту'
)
with st.expander(
label='Показать примеры сообщений со скрытыми контактными данными'
):
st.write(
"""
Ма8ш9и9н9а6 в 0хо0ро4ш4е2м9 состоянии
Новый велосипед Работает всё Звонить на 8 девятьсот восемь 1976829
Беспроводная точка доступа маршрутизатор Моя Почта xopkin317 mailru
My Отличный телефон TW практически новый ich хороший экран, без трещин lork не падал ing92
"""
)
re_res = tools.get_re_pred(user_text)
if 'Есть контактная информация' in re_res:
st.success(f'Regex: {re_res}')
else:
st.error(f'Regex : {re_res}')
tf_idf_res = tools.get_tf_idf_pred(user_text)
if 'Есть контактная информация' in tf_idf_res:
st.success(f'TF_IDF: {tf_idf_res}')
else:
st.error(f'TF_IDF: {tf_idf_res}')
bert_res = tools.get_bert_prediction(user_text)
if 'Есть контактная информация' in bert_res:
st.success(f'BERT: {bert_res}')
else:
st.error(f'BERT: {bert_res}')
with st.form(key='quiz'):
right_answers_count = 0
st.write('QUIZ')
answer = st.radio(
label='Что такое регулярные выражения?',
options=[
'Модель машинного обучения',
'Аналог TF-IDF',
'Инструмент проверки строк на соответствие какому-либо шаблону',
'Инструмент для классификации сообщений пользователя',
'Выражения, которые регулярно используются разработчиками',
'WEB фреймворк',
]
)
if answer == 'Инструмент проверки строк на соответствие какому-либо шаблону':
right_answers_count += 1
answer = st.radio(
label='Как пользователи обходят правила модерации сервиса?',
options=[
'Пишут в поддержку',
'Изменяют сообщения, маскируя запрещенный контент',
'Записывают голосовые сообщения',
'Пользуются другими сервисами, без модерации'
]
)
if answer == 'Изменяют сообщения, маскируя запрещенный контент':
right_answers_count += 1
answer = st.radio(
label='Что такое TF-IDF?',
options=[
'Вид регулярных выражения',
'Система модерации текстовых сообщений',
'Запчасть автомобиля',
'Мера оценки значимости слова в документе',
'Модель машинного обучения',
'Корпус текстов',
]
)
if answer == 'Мера оценки значимости слова в документе':
right_answers_count += 1
answer = st.radio(
label='Что оценивает TF-IDF?',
options=[
'Нужно ли отправлять сообщение на модерацию или нет',
'Значимость слова в документе',
'Частоту слова',
'Обратную частоту слова в документе'
]
)
if answer == 'Значимость слова в документе':
right_answers_count += 1
answer = st.radio(
label='Что такое BERT?',
options=[
'Персонаж из мультика "Улица Сезам"',
'Нейронная сеть от Google',
'Система модерации сообщений',
'Система оценки соответствия сообщений правилам организации и законам',
'Вид регулярных выражений'
]
)
if answer == 'Нейронная сеть от Google':
right_answers_count += 1
answer = st.radio(
label='Как обучается BERT?',
options=[
'На GPU',
'Никак, Google уже обучила ее, нам остается только пользоваться готовой',
'Маскируя 15% слов символом [MASK] и пытаясь предсказать спрятанные слова'
]
)
if answer == 'Маскируя 15% слов символом [MASK] и пытаясь предсказать спрятанные слова':
right_answers_count += 1
answer = st.radio(
label='В каком виде подается информация на вход нейросети BERT?',
options=[
'Как есть без изменений',
'В виде векторов с числами, обозначающими целевое слово и близких к нему по смыслу из словаря',
'В виде сконкатенированных строк всего обучающего датасета',
'В виде списка текстов'
]
)
if answer == 'В виде векторов с числами, обозначающими целевое слово и близких к нему по смыслу из словаря':
right_answers_count += 1
answer = st.radio(
label='BERT учитывает контекст в предложениях?',
options=[
'Нет',
'Да'
]
)
if answer == 'Да':
right_answers_count += 1
res = st.form_submit_button()
if res:
st.info(f'Количество правильных ответов {right_answers_count} из 8.')
if right_answers_count <= 6:
st.warning('Для прохождения блока необходимо правильно ответить хотя бы на 7 вопросов.')
else:
st.success('Отлично! Блок пройден.')
|