Как стать автором
Обновить

Комментарии 44

Черт, вот на чем надо тренировать эти ваши рекуррентные сети. К черту Шекспира, нам нужен генератор пирожков! Не поделитесь, откуда выборку брали и можно ли достать еще?

По теме — выглядит круто, никогда не занимался текстом, но word2vec издалека выглядел очень интересной штукой. Дилетантский вопрос — а сделать условный шаг дальше и семантически сравнивать предложения/фразы кто-нибудь же наверняка пробовал, да?
Пирожки (и порошки :)) надёргал в интернете, сколько было не лень. Даже пришлось небольшой скриптик выдумывть, чтобы отсеять повторы. Честно говоря, сам был бы рад найти увесистый сборник одним файлом, но не нашёл.

Обрабатывать фразы word2vec, конечно же, уже пробовали (всё украдено до нас :)) — просто сливали несколько слов в одну лексему, а потом всё то же самое. В английском это проще, в русском сложней — у нас, в виду синтетичности языка, многие слова сами по себе уже маленькие предложения, отчего грамматическая нормализация вносит гораздо больше смысловых искажений.
На всякий случай — вот сайт с целой кучей пирожков perashki.ru
Обучил lstm Карпатого на github.com/drafterleo/pie-poem/blob/master/poems.txt. Гласные и строчки считать более-менее научилось, слова — примерно, согласования никакого.

я был живёшь веселою клей
я тронангию истязный
чем банков можно сементами
стрелы не знала и назвать

прохожих как внором из солнцев
возьмите на девять силят
я надо открываю главку
и сразу сершия с небюс
Черт, вы меня опередили) Сколько слоев/нейронов? Я пару ночей гонял два по 512, получается примерно такая же фигня:

мы все умер и под другой
тога значит режет стены
в водьше наступили к куру
труда не выновить в культор

кричит олег а под летом
воя с насон присопяты
закончится веси беспорность
а теля понячный продкайся

с Шекспиром у Карпатого как-то лучше получалось, так что я теперь пробую три слоя)
2 слоя, 128 нейронов
Нейросеть :)
>>  pprint(ap.similar_poems("нейросеть", pm, w2v, topn=5))
[('малошумящий усилитель'
  'для усиления шумов'
  'производимых аппаратом'
  'для шумоподавления',
  0.12743493124366839),
 ('лилит не женщина а просто'
  'эфир лилейной кислоты'
  'по аналогии с боратом'
  'который вовсе не казах',
  0.11525529312273997),
 ('шум квантования пространства'
  'в диапазоне микроволн'
  'наш мир дискретный отличает'
  'от теплых ламповых миров',
  0.10532414661844355),
 ('теоретически я умер'
  'осталось только подогнать'
  'ряд главных функций организма'
  'под этот жесткий постулат',
  0.10308405684535353),
 ('налаживаю генератор'
  'и добиваюсь чтобы ток'
  'был строго синусоидален'
  'как наши встречи с зульфиёй',
  0.10109047862104875)]



Зарядить нейросеть в качестве генератора — классная идея, конечно. Хотя результаты (на данном этапе) выглядят жутковато. Смотришь и начинаешь постигать природу шизофрении. Кстати, а как эти штуки показывают себя на абстрактных грамматиках? Быстро раскалывают алгоритм?
Я настолько никогда не занимался текстом, что даже не знаю, что это такое) Плохие результаты на текущем этапе, по крайней мере у меня, кажется, объясняются для начала тем, что я скармливаю сети слишком маленький кусок данных для предсказания следующей буквы (нужно по куску из 20 букв предсказать 21-ю). По той же ссылке на Карпатого у него сотня букв — попробую теперь так)

Насколько я понимаю, на пальцах это должно работать примерно так — сеть должна держать в памяти такое число знаков, чтобы в него помещалась структура, которую мы хотим воспроизвести. Если говорить только о рифме, то получается, что нужно помнить последние две строки, скажем. Если о смысле — то четыре, и тут мне уже просто интересно, насколько это вообще реально — воспроизвести осмысленные (согласованные) четыре строки подряд.
Только она держит не сами знаки, а какую-то метаинформацию о них (см. картинки).

Я бы предположил, что проблема еще и в малом размере обучающей выборки (Шекспира было в полтора раза больше).
1.4 в UTF8. Т.е. полезного почти в 2 раза меньше.
леча на резу ладонотки
взяли рыбаки из клады
друг все со рут огонь негромко
сведляна сердце пропагал

с конечно вечером меняешь
а у косу свою цену
елена мне мы пять восьмого
и больше не хочу подходь

вокруг безмолвных и глазами
на так без осенью неспод
чтобы начальствуют кладбанка
и просто мружен в руклилом

олег геннадий ким и горя
сказала лазкой на кира
же крикнул идеолый сапам
вятель на свадьбу в николай


256 нейронов, 2 слоя, 3.3мб обучающая выборка
Абстрактные грамматики — штука в общем-то простая. По сути, вероятностный генератор (алгоритм) последовательностей символов на марковской цепи (несколько лет назад делал по этой теме программку, правда с уклоном в людей, а не в нейросети :)). Последовательности, сгенерированные разными алгоритмами, классифицируются на раз (через n-граммы или наивным байесом), а вот реконструировать алгоритм по последовательности (т.е. построить изоморфный генератор) — задача куда менее тривиальная. Судя по тому, что я вижу (эксперименты с шекспиром и пирожками), рекуррентные сети должны щёлкать абстрактные грамматики как семечки. По идее — школьная задачка в этой сфере (ведь можно легко проверить результат, посчитать степень корреляции генерируемых последовательностей). Но в сети ничего не нашёл (впрочем, искал не очень глубоко :)). Быть может, вам что-нибудь попадалось об этом?
О, спасибо за ликбез) Быстрый гуглинг выдал вот такую штуку.
Да, это оно. Взаимное спасибо. Правда, там, насколько я разобрался, основной упор делается на распознавание грамматики, а не на генерацию «фальшивых» (в хорошем смысле этого слова :)) последовательностей. Хотя, если рекуррентная сеть может узнавать, то она, видимо, способна и продуцировать «подделки» малоотличимые от оригинала. Так?
Ещё стоило бы отметить, что дистрибутивная семантика является одним из краегольных камней алгоритмов глубокого обучения (и вообще NN и многих вероятностных моделей), поэтому очень полезно и важно с ней разобраться :-)

Подробнее можно посмотреть в видео-лекциях школы по глубокому обучению вот тут и ещё можно глянуть крутой курс от Udacity вот тут.
Насколько я смог уловить поэтику, «порошок» это искажённое произнесение «пирожка» — вроде как по смыслу то же самое, а по форме немного другое :).
Не совсем так. Пирожок — 9-8-9-8, ямб без рифмы, порошок или порох — 9-8-9-2, с рифмой 2-4, если память не изменяет. Исторически порошки появились из пирожков, но стали вполне себе самостоятельным форматом.
Есть еще другие похожие формы. Самая распространенная — двустрочная, например:
зачем учить нас как работать
вы научитесь как платить
© bazzlan
Вот видите как замечательно, я в порошке увидел озорного сынишку пирожка, а вы узрели воспламеняющий порох. Поэзия однако — стихия субъективной глубины :). В целом, соглашусь, порошки за счёт (неожиданной, как правило) рифмовки «отжигают» подинамичней пирожков. На мой взгляд, если хороший пирожок что-то в душе разминирует, то хороший порошок наоборот — подрывает. Вот мой любимый (и кажется в тему :))
лишает сна срывает крышу
и переводит речь на мат
незапихуемость идей
в формат

© ракша
я в порошке увидел озорного сынишку пирожка, а вы узрели воспламеняющий порох.


хм, а мне тут виделась отсылка к мему «порошок уходи» :)
Вообще, пирожки можно печь на лету, если внутренний голос на ритм настроить. Плохие, но формально — пирожки.
Настолько просто это делать
что я в полуночном бреду
решил скостылить быстро скриптик
и всех поэтов заменить

И вообще да, надо в эту сторону подумать. А вы могли бы прислать ваш корпус пирожков для таких целей?
В посте есть ссылка. Я тоже прямо заинтересовался)
С этими пирожками — главное не объестся. Я вот, чувствую, за последнюю неделю переел. Но всё же, если, вдруг, пополните корпус пирожков — надеюсь на ссылку алаверды :).
Да это же шикарно!!! как только появится свободное время, реализуются подобное у себя на машине и улучшу базу пирожков ^_^
Очень интересно, спасибо! А по теории что почитать рекомендуете?
Откровенно говоря, затрудняюсь ответить, ибо не являюсь большим специалистом в этой области. Если что-то обзорное по дистрибутивной семантике — есть неплохая лекция Андрея Кутузова. Если поразбираться, что под капотом word2vec — вот, например, подробная статья со схемами и матаном.
Как я правильно понимаю похожесть слов «корабль» и «судно» уже встроенны в word2vec?
Ай ай, я уже нашел про модель лексических векторов.
;)

>> w2v.similarity("судно_S", "корабль_S")

0.87323218690957494

>> w2v.most_similar(positive=["судно_S"])

[('корабль_S', 0.873232364654541),
 ('шхуна_S', 0.7688922882080078),
 ('пароход_S', 0.7471548914909363),
 ('катер_S', 0.720923662185669),
 ('крейсер_S', 0.6798930764198303),
 ('парусник_S', 0.6786847114562988),
 ('яхта_S', 0.6684943437576294),
 ('фрегат_S', 0.6651678085327148),
 ('шлюпка_S', 0.6553121209144592),
 ('теплоход_S', 0.6479202508926392)]
а что судно — утка? (чисто «научный» интерес))… особенно в сравнении с симили судна с другими водоплавающими (например — гусём)
и потом корабль с ними же…
Утки, гуси, корабли...
In[23]: w2v.similarity("судно_S", "утка_S")
Out[23]: 0.089143973072140115
In[24]: w2v.similarity("судно_S", "гусь_S")
Out[24]: 0.097027585466394742
In[25]: w2v.similarity("судно_S", "лебедь_S")
Out[25]: 0.12152089704781086
In[26]: w2v.similarity("корабль_S", "утка_S")
Out[26]: 0.054613116159502359
In[27]: w2v.similarity("корабль_S", "гусь_S")
Out[27]: 0.086045645971750101
In[28]: w2v.similarity("корабль_S", "лебедь_S")
Out[28]: 0.1518852487994459


При желании можно поиграть с этим онлайн
спасибо, надо пощупать…
Благодаря стараниям коллеги wiygn (не поленился же человек, наковырял изюму :)) корпус пирожков существенно пополнился (теперь их больше 7500). Мусор я, вроде, вычистил, повторы своими кустарными средствами поудалял, однако если какой-нибудь добрый человек найдёт время перепроверить 1.3 мегабайта чистой поэзии — будет вообще хорошо.

чистая поэзия :)
>> pprint(similar_poems("чистая поэзия", pm, w2v, topn=5))
[('из современной русской прозы'
  'я выделил бы тот роман'
  'который был написан вами'
  'а выделив бы удалил',
  0.13792188721288026),
 ('олегу маша показалась'
  'прекрасной чистой и святой'
  'олег же маше показался'
  'в дырявых бежевых носках',
  0.13690850835700927),
 ('когда любовь переполняет'
  'то выливается она'
  'взаимная посредством секса'
  'а безнадежная в стихах',
  0.12459351854737398),
 ('я томик ленина листаю'
  'страницы гладки и чисты'
  'как кожа юной комсомолки'
  'и также пахнут молоком',
  0.12329326742852674),
 ('зухра великое искусство'
  'она нисходит не ко всем'
  'и те кому она даётся'
  'не все овладевают ей',
  0.11324476203692123)]

Ух, как интересно. Могу поделиться базой со своего Поэтория. Думаю теперь, вот, реализовать что-то подобное у себя.
Конечно же делитесь! Это прямо-таки из серии «мечты сбываются» — буквально неделю назад грезил о базе Поэтория :). Кстати, могли бы вы предоставить эту базу вместе с рейтингами — есть огромное желание протащить поэтический материал через машинное обучение на предмет предсказания качества (популярности) пирожка. Поверить, так сказать, алгеброй гармонию — посальерить моцартов :).
Надо было не грезить, а написать сразу :) Отправил контакты в личку.
Опять-таки при содействии wiygn база пирожков существенно подросла (теперь в ней порядка 33000 штук — poems_33000.txt).

Примеры «насыщенного» поиска по экзотичным словам:

Бювар
>> pprint(ap.similar_poems("бювар", pm, w2v, topn=5, use_associations=True))
[('у программиста две коробки'
  'коробка а коробка бэ'
  'в коробке а коробка бэ а'
  'в коробке бэ коробка а',
  0.38437933799548024),
 ('так и живёт она с котами'
  'фиалками и сундуком'
  'в котором кожаная плётка'
  'и мой забытый портсигар',
  0.35700261151349105),
 ('карандаши лежат в пенале'
  'пенал в портфеле а портфель'
  'на чердаке среди другого'
  'сентиментального нытья',
  0.34135048477737989),
 ('забыл ключи и ноты тоже'
  'и даже паузы забыл'
  'и что за палочка позвольте'
  'лежит в кармане у меня',
  0.3361660286232277),
 ('олег анальные конфеты '
  'купил и бережно несёт '
  'не в рюкзаке и не в барсетке '
  'и даже не в кармане брюк',
  0.32774677611233893)]

Трензель
>> pprint(ap.similar_poems("трензель", pm, w2v, topn=5, use_associations=True))
[('не плюйтесь митя не верблюд вы'
  'не ржите фёдор вы не конь'
  'вы иннокентий не курите'
  'ведь вы же вы ж не человек',
  0.35941473642985028),
 ('седлай кобылу вороную'
  'поскачем в крым поскачем в степь'
  'мы тыщу триста километров'
  'преодолеем невзначай',
  0.33290767669677734),
 ('али седлает дромадера'
  'зейнаб и фатима стоят'
  'а может не зейнаб а лейла'
  'в скафандрах чёрных не поймёшь',
  0.33117986192890242),
 ('илья ильич гнедую лошадь'
  'ведет в конюшню под уздцы'
  'и изнутри на две щеколды'
  'надежно запирает дверь',
  0.31826136906941732),
 ('я дискжокей а это значит'
  'люблю пластинки объезжать'
  'бывало как увижу диски'
  'седлаю и скачу верхом',
  0.30559972127278645)]

Елань
>> pprint(ap.similar_poems("елань", pm, w2v, topn=5, use_associations=True))
[('мой город спит и видит поле'
  'а мой район в нём видит лес'
  'и речки спят и видят речки'
  'такие же но без имён',
  0.30486257452713816),
 (' разбит мой город на районы'
  'разбит район мой на дома'
  'мой дом разбит немецкой бомбой'
  'а немец нашими разбит',
  0.29329273747462853),
 ('внутри у николая горы'
  'и океаны и леса'
  'снаружи николая тоже'
  'но не такие как внутри',
  0.28508076137966581),
 ('пришли в деревню супостаты'
  'а изуверы в города'
  'а к нам в домишко на отшибе'
  'пришла весна и комсомол',
  0.2843143396210252),
 ('я назарет из иисуса'
  'здесь все в округе города'
  'и все селения поменьше'
  'из иисусов состоят',
  0.27356621071144388)]

Бурлеск
>> pprint(ap.similar_poems("бурлеск", pm, w2v, topn=5, use_associations=True))
[('играл чайковского шаинский '
  'не угадаете на чём '
  'ну хорошо не буду мучать '
  'на сцене в пьесе про себя',
  0.22649443591082538),
 ('мы композиторы семёны'
  'мы написали вам сонат'
  'сюит симфоний и секвенций'
  'а вы борщи несите нам',
  0.22268539004855686),
 ('оксане нравилось фламенко'
  'олегу классика и джаз'
  'они вдвоём со сцены пели'
  'про лагеря и мусоров',
  0.22202377988581071),
 ('семён седьмой литературный'
  'известный персонаж подряд'
  'играет молча в грустной пьесе'
  'завязанные рукава',
  0.21163431803385416),
 ('играет мыскина неплохо'
  'неплохо моцарт сочинял'
  'и только секс с тобой прекрасен'
  'с тобой одной с тобой одной',
  0.21109667530766241)]

Фронда
>> pprint(ap.similar_poems("фронда", pm, w2v, topn=5, use_associations=True))
[('осталось несколько столетий'
  'и мы построим коммунизм'
  'без мерзкой власти капитала'
  'без войн без секса без людей',
  0.23658270835876466),
 ('имею комплексы и взгляды'
  'а также принципы и вкус'
  'идеи и мировоззренье'
  'в ответ прошу оральный секс',
  0.21776164524138919),
 ('у ольги изменился запах'
  'а кажется что интеллект'
  'и политические взгляды'
  'и форма челки и зубов',
  0.20957694230256257),
 ('власть добрократов под собою'
  'имеют крепких два столба'
  'все то что сочинил шаинский'
  'и политический террор',
  0.20927111307779947),
 ('вступив в сообщество плутархов'
  'я понял что не прогадал'
  'у власти нынче плутократы'
  'а я плутарх я их монарх',
  0.20429160859849718)]

Синекура
>> pprint(ap.similar_poems("синекура", pm, w2v, topn=5, use_associations=True))
[('для семинаров по убийству'
  'пособий просто не достать'
  'стипендий ленинских не платят'
  'и блата нет ни у кого',
  0.19780904275399666),
 ('аванс у дъявольской зарплаты'
  'сиеминутен но велик'
  'аванс божественной ничтожен'
  'но даже за чертой нетленн',
  0.19452412923177084),
 ('вступайте в войско чингизхана'
  'оклад семь тыщ двойной паёк'
  'декретный отпукс саноторий'
  'страховка пенсия престиж',
  0.18662718570593631),
 ('олег стоит не понимает'
  'откуда столько голосов'
  'откуда этот свет и гдеже'
  'его зарплата и очки',
  0.18360155600088615),
 ('оксана не дала олегу'
  'олег не дал стране угля'
  'страна не даст врачу зарплату'
  'а врач не даст оксане жить',
  0.1772317091623942)]

Латифундия
>> pprint(ap.similar_poems("латифундия", pm, w2v, topn=5, use_associations=True))
[('россия в крепостных у чуба '
  'который айс к людям как лед '
  'он взял в концессию у вовы '
  'продажу света и тепла',
  0.19776902198791504),
 ('герасим крепостного права '
  'четвертый год в деревне нет'
  'уебище глухонемое'
  'перетопил нам всех собак',
  0.19733301798502603),
 ('купил в балашихе участок'
  'построил дом и нанял слуг'
  'и чувствую как неизбежно'
  'я чьей то становлюсь мечтой',
  0.19490887901999734),
 ('сначала я дружил дворами'
  'а после стал дружить семьёй'
  'и коллективом позже дачей'
  'теперь диагнозом дружу',
  0.18583927154541016),
 (' разбит мой город на районы'
  'разбит район мой на дома'
  'мой дом разбит немецкой бомбой'
  'а немец нашими разбит',
  0.17606544494628906)]

Ригоризм
>> pprint(ap.similar_poems("ригоризм", pm, w2v, topn=5, use_associations=True))
[('я не люблю себя за скотство'
  'за подлость мелочность и лень'
  'сильней всего конечно бесит'
  'тупая ненависть к себе',
  0.24003094121029503),
 ('адам произошел от бога'
  'и унаследовал его'
  'агрессию и истеричность'
  'и склонность к постоянной лжы',
  0.23890022203034045),
 ('он был не просто так евгений'
  'он был евгений смерть врагу'
  'а кто враги бездушность подлость'
  'мздоимство косность клевета',
  0.23708248138427734),
 ('есть героин для героизма'
  'есть для гашения страстей'
  'гашыш ещо для оптимизма'
  'немного опиума есть',
  0.21587917539808485),
 ('остановитесь я же просто'
  'производитель пирожков'
  'их простота и гениальность'
  'не повод поклоняться мне',
  0.21307498333500882)]

Вертеп
>> pprint(ap.similar_poems("вертеп", pm, w2v, topn=5, use_associations=True))
[('а после рюмочной и клуба'
  'еще был винный погребок'
  'избыточный и тошнотворный'
  'как тридцать третье фуэте',
  0.22720870265254267),
 ('в тоннелях метрополитена'
  'есть андерграундный кабак'
  'там крысы пляшут зазывая'
  'самоубийц на огонек',
  0.21550264812651135),
 ('о да завидное местечко'
  'вы подобрали мне но где'
  'здесь магазины бары клубы'
  'и люди все скажите где',
  0.21172858874003092),
 ('то дес то клуб то дес то клуб то'
  'дес то клуб то дес то клуб то'
  'дес то клуб то дес то клуб то дес'
  'то клуб то дес то клуб то дес',
  0.20926956696943802),
 ('оксана ходит с голой жопой'
  'в кафе в химчистку в магазин'
  'ей кажется что так удобней'
  'а люди падают без чувств',
  0.20475262006123859)]
может прикрутить к Поэторию сервис — «сгенерировать пирожок на тему»?
Да, поэтический оракул (или пирожковый И-Цзин :)) было бы прикольно запустить. Однако на данный момент есть ряд сложностей (впрочем, я ни разу не специалист по прикручиванию сервисов и, быть может, теперь это никакие не сложности). Во-первых, память — нужно порядка 500mb оперативки для загрузки моделей. Во-вторых, скорость — у меня сейчас поиск по 33000 базе занимает от секунды до десяти (в зависимости от количества слов в запросе) и конкретно пригружает все ядра. Можно, конечно, все пирожки заблаговременно представить в формате векторных матриц, но вряд ли это ускорит процесс принципиально.
Я как-то делал генератор хайку и написал под это дело парсер слов и предложений на слога, что позволило добиться поэтичности генерируемого текста.
https://github.com/tumikosha/iPoet
Но со смысловой увязкой предложений были проблемы. Думал попробовать подбирать слова подходщие по смыслу с помощью word2vec. Ваша публикация убедила меня в перспективности этого подхода. Спасибо!
Собрал модели по афоризмам Ежи Леца и гарикам Губермана:

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации