Facebook. Переводя очередной ценник в супермаркете, я уже не ощущаю тёплое дыхание киберпанка — это будничная реальность. А ведь исследователи почти столетие бились над алгоритмами машинного перевода, половину из этого периода — без особых успехов.

Однако именно их наработки теперь лежат в основе всех современных систем обработки языка: от поисковиков до микроволновок с голосовым управлением. Поговорим о том, как развивался и как устроен онлайн-перевод.

Наша история начинается в 1933 году. Советский ученый Пётр Троянский обращается в Академию наук СССР с изобретённой им «машиной для подбора и печатания слов при переводе с одного языка на другой». Машина была крайне проста: большой стол, печатная машинка с лентой и плёночный фотоаппарат. На столе лежали карточки со словами и их переводами на четырёх языках.

Машина Троянского (иллюстрация по описаниям, а фотографий, естественно, не сохранилось)

Оператор брал первое слово из текста, находил карточку с ним, фотографировал её, а на печатной машинке набирал его морфологическую информацию: существительное, множественное число, родительный падеж.

Её клавиши были модифицированы для удобства, каждая однозначно кодировала одно из свойств. Лента печатной машинки и плёнка камеры подавались параллельно, на выходе формируя набор кадров со словами и их морфологией:

Полученная лента отдавалась знающим конкретные языки лингвистам, которые превращали набор фотографий в связный литературный текст. Получается, чтобы переводить тексты, как оператору, так и лингвистам требовалось знать только свой родной язык.

Машина Троянского впервые на практике реализовала тот самый «промежуточный язык» (interlingua), о создании которого мечтали ещё Лейбниц и Декарт.

По классике в СССР изобретение признали ненужным, Троянский умер от стенокардии, 20 лет пытаясь доработать детище. Никто в мире так и не знал о машине, пока его патенты не откопали в архивах двое других советских учёных в 1956 году.

Произошло это неслучайно. Они искали ответ на вызов холодной войны, ведь 7 января 1954 года в штаб-квартире IBM в Нью-Йорке произошёл Джорджтаунсий эксперимент. Компьютер IBM 701 впервые в мире автоматически перевёл 60 предложений с русского языка на английский.

«Девушка, которая не понимает ни слова на языке Советов, набрала русские сообщения на перфокартах. Машинный мозг сделал их английский перевод и выдал его на автоматический принтер с бешеной скоростью — две с половиной строки в секунду», — сообщалось в пресс-релизе компании IBM.

Газеты пестрили ликующими заголовками, но никто не говорил, что примеры для перевода были тщательно подобраны и протестированы, чтобы исключить любую неоднозначность. Для повседневного использования эта система подходила не лучше карманного разговорника.

Но гонка вооружений была запущена. Канада, Германия, Франция и особенно Япония тоже подключились к гонке за машинный перевод. Сорок лет учёные бились в попытках улучшить машинный перевод, но тщетно. В 1966 году американский комитет ALPAC опубликовал свой знаменитый отчёт, в котором назвал машинный перевод дорогим, неточным и бесперспективным.

Отчёт рекомендовал больше сфокусироваться на разработке словарей, чем на машинном переводе, из-за чего исследователи из США практически на десятилетие выбыли из гонки.

Несмотря на всё, именно попытки учёных, их исследования и наработки впоследствии лягут в основу современной обработки естественного языка (Natural Language Processing). Поисковики, спам-фильтры, персональные ассистенты — всё это появится благодаря тому, что кучка стран сорок лет подряд пытались шпионить друг за другом.

Машинный перевод на основе правил — Rule-based Machine Translation (RBMT)

Идеи машинного перевода на основе правил начали появляться ещё в 1970-х годах. Учёные подсматривали за работой лингвистов-переводчиков и пытались запрограммировать свои большие и медленные «компуктеры» повторять за ними. Их системы состояли из:

  1. Двуязычного англо-русского словаря.
  2. Набора лингвистических правил под каждый язык (существительные женского рода, оканчивающиеся на -а/-я).

В общем-то всё. По желанию они дополнялись списками имён, корректорами орфографии и транслитераторами.

Promt и Systran — самые известные примеры RBMT-систем. Например, фраза: «Охладите траханье, углепластик, я рассматриваю её пользу». Золотое время же. Aliexpress вон до сих пор так переводит. Но даже у них были свои нюансы и подвиды.

Системы дословного перевода (Direct Machine Translation)

Это самый простой способ машинного перевода, понятный любому пятикласснику. Делим текст по словам, переводим каждое, немножко правим морфологию, чтобы звучало не криво, согласуем падежи, окончания и остальной синтаксис.

Специально обученные лингвисты по ночам пишут правила под каждое слово. На выходе получаем что-то переведённое. Чаще всего полное говно. Только лингвистов зря попортили. В современных системах подход не используется вообще, рассказываю, чтоб чисто поржать.

Трансферные системы (Transfer-based Machine Translation)

В них мы не кидаемся сразу переводить по словарю, а немного готовимся. Разбираем текст на подлежащее, сказуемое, ищем определения и всё остальное, как учили в школе. Взрослые дядьки говорят: «Выделяем синтаксические конструкции». После этого в систему мы уже не закладываем правила перевода каждого слова, а манипулируем целыми конструкциями.

В теории даже можем добиться более-менее неплохой конвертации порядка слов в языках. На практике всё ещё тяжело, лингвисты по-прежнему гибнут от физического истощения, а перевод получается фактически дословный. С одной стороны, проще: можно задать общие правила согласования по роду и падежу. С другой — сложнее: сочетаний слов намного больше, чем самих слов. Каждый вариант не учтёшь вручную.

Интерлингвистические системы (Interlingua Machine Translation)

Полностью конвертируем исходное предложение в некое промежуточное представление, единое для всех языков мира — интерлингва (interlingua). В ту самую интерлингву, которой грезил сам Декарт. Специальный метаязык, правила которого едины и покрывают все языки мира, тем самым превращая перевод в техническую задачу перегона туда-сюда.

Специальные парсеры затем конвертируют эту интерлингву в нужный язык и вот она — сингулярность.Часто интерлингву путают с трансферными системами, ведь там тоже есть конвертация. Однако в трансферных системах правила конвертации пишутся под два конкретных языка, а в интерлингвистической между каждым языком и интерлингвой. Добавив в интерлингвистическую систему третий язык, мы сможем переводить между всеми тремя, а в трансферной — нет.

В реальной жизни всё оказалось не так радужно. Создать универсальную интерлингву вручную оказалось крайне сложно. Некоторые учёные жизни свои положили на это. Ничего не получилось, однако благодаря им у нас появились методы морфологического, синтаксического и даже иногда семантического анализа. Одна только модель «Смысл <-> Текст» чего стоит. Но сама идея промежуточного языка еще вернётся к нам позже. Надо будет подождать всего 30 лет.

Как можно заметить, все RBMT тупы, ужасны, поэтому сейчас редко используются. Разве что в специфических местах вроде перевода метеосводок. Среди плюсов RBMT отмечают морфологическую точность (не путает слова), воспроизводимость (все переводчики получат одинаковый результат) и возможность затюнить под предметную область (обучить специальным терминам экономистов или программистов).

Даже если представить, что учёным удалось бы создать идеальную RBMT, а лингвистам заложить в неё все правила правописания, за дверью их уже поджидало веселье — исключения. Неправильные глаголы в английском, плавающие приставки в немецком, суффиксы в русском, да и просто ситуации, когда «у нас так не говорят, надо вот так».

Попытка учесть все нюансы оборачивается миллионами потраченных зря человекочасов. Множество правил всё равно не решает главной проблемы — омонимии. Одно и то же слово может иметь разный смысл в зависимости от контекста, а значит, отличается и его перевод. Вспоминается пример с одной из старых лекций Сегаловича: «Эти типы стали есть на складе». Он говорил, что может найти четыре разных варианта прочтения этого предложения. А вы?

Наши языки развивались отнюдь не на основе грамматик и правил, о которых любят рассуждать лингвисты. Они больше зависят от того, кто на кого напал и завоевал за последние триста лет. Вот как мне теперь обучить этому машину?

За сорок лет холодной войны учёные так и не смогли найти внятного решения. RBMT сдох.

Машинный перевод на примерах — Example-based Machine Translation (EBMT)

В битве за машинный перевод в те годы была особенно заинтересована Япония. Там не было холодной войны, но были свои причины: крайне мало кто в стране знал английский. Это сулило большие трудности на вечеринке наступающей глобализации, из-за чего японцы были мотивированы найти рабочий метод машинного перевода.

Англо-японский перевод на основе одних только правил сложен, строение языков отличается, почти все слова приходится переставлять и добавлять новые.

В 1984 году учёному университета Киото по имени Макото Нагао приходит идея. А что если не пытаться каждый раз переводить заново, а использовать уже готовые фразы?

Предположим, нам надо перевести предложение «я иду в магазин». Где-то в заначке у нас уже есть перевод похожей фразы «я иду в театр» и словарь с переводом слова «магазин». Мы ведь можем как-то попытаться вычислить разницу и перевести только одно слово в имеющемся примере, не похерив остальные конструкции. И чем больше у нас примеров — тем лучше перевод.

Я же тоже так строю фразы на незнакомых языках

Историческая важность метода была в том, что учёные всего мира впервые прозрели: можно не тратить годы на создание правил и исключений, а просто взять множество уже имеющихся переводов и скормить их машине. Это была ещё не революция, но шаг к ней. До революции и изобретения статистического перевода оставалось пять лет.

Статистический машинный перевод — Statistical Machine Translation (SMT)

На рубеже 1990 года в исследовательском центре IBM впервые показали систему машинного перевода, которая ничего не знала о правилах и лингвистике. Учёные показали бездушному компьютеру очень много одинаковых текстов на двух языках и заставили его разбираться в закономерностях самому.

Идея была проста и одновременно красива: берём одно предложение на двух языках, разбиваем его по словам и пытаемся сопоставить каждое слово с его с переводом. Повторяем эту операцию где-то 500 млн раз, а машина считает, сколько раз у нас слово das Haus переводилось как house, building, construction, и так далее.

Наверное, чаще всего это был house, его и будем использовать. Заметьте, мы не задали ни правил, ни словарей. Машина сама всё нашла, руководствуясь чистой статистикой и логикой «люди переводят вот так, значит, и я буду». Так родился статистический перевод.

Точность таких переводчиков оказалась заметно выше всех предыдущих, а разработка не требовала никаких лингвистов. Находим больше текстов — улучшаем перевод. Одна проблема: как машина догадается, что для das Haus парой является именно house, а не любое другое слово из предложения? Порядок слов-то разный, откуда мы знаем как именно надо разбить и найти нужные слова?

Ответ: никак. В начале работы машина с равной долей вероятности считает, что слово das Haus переводится как любое из слов имеющегося предложения. Когда она встречает das Haus в других предложениях, то количество переводов das Haus как house начинает увеличиваться с каждым разом.

Это называется «алгоритмом выравнивания слов» (word aligment). Типичная задача машинного обучения, такие решают в университетах. Машине нужны миллионы предложений на двух языках, чтобы набрать статистику по каждому слову. И где столько взять? Так вон, в Европарламенте и совете ООН ведут конспекты заседаний на языках всех стран-членов, их и возьмём. Сейчас они даже открыли их для скачивания: UN Corpora и Europarl Corpora.

Кишки статистического перевода в Google Translate. Google не только показывает вероятности, но и считает обратную статистику

Статистический перевод по словам — Word-based SMT

Первые системы статистического перевода опять начали с деления по словам. Это казалось логично и просто. Первую изобретённую модель статистического перевода в IBM назвали IBM Model 1. Изящно, да. Догадайтесь, как назвали вторую?

Model 1: мешок слов

Классический подход — делим всё на слова и считаем статистику. Никакого учёта порядка или перестановок. Из хитростей разве что это: Model 1 умела переводить одно слово в несколько. Der Staubsauger (пылесос) легко превращался в Vacuum Cleaner, но обратно уже как повезёт. На Python можно найти простенькие реализации: shawa/IBM-Model-1.

Model 2: учёт порядка слов в предложении

Отсутствие знаний о порядке слов в языках стало проблемой для Model 1. В некоторых он очень важен. Поэтому в Model 2 стали запоминать, на каком месте слово появляется в переведённом предложении. Добавили промежуточный шаг — после перевода машина пыталась переставить слова местами так, как, она думала, будет звучать более естественно. Стало лучше, но всё ещё хреново.

Model 3: добавление отсутствующих слов

Часто при переводе появляются новые слова, которых не было в оригинальном тексте. В немецком языке внезапно вылезают артикли, в английском вставляют глагол do где ни попадя. «Я не хочу хурмы» → «I do not want persimmons». Чтобы решить эту проблему, в Model 3 добавили два промежуточных шага:

  1. Вставка маркеров (NULL-слов) на те места, где машина подозревает необходимость нового слова.
  2. Подбор нужного артикля, частицы или глагола под каждый маркер.

Model 4: перестановки слов

Model 2 хоть и учитывала порядок слов в предложении, но ничего не знала про перестановки слов между собой. Часто при переводе надо, например, поменять существительное и прилагательное местами.

Тут, сколько ни запоминай их порядок по всему предложению, — лучше не станет. Потому в Model 4 стали учитывать ещё и так называемый «относительный порядок». Если при переводе два слова постоянно менялись друг с другом — модель это запоминала.

Model 5: багфиксы

Особо ничего нового. В Model 5 добавили параметров для обучения и пофиксили проблемы, когда два слова конфликтовали за место в предложении.

Несмотря на всю революционность, Word-based системы по прежнему ничего не могли поделать с падежами, родом и омонимией. Каждое слово они переводили единственным, по их мнению, верным способом. Сейчас такие системы не используются, их заменил более продвинутый метод — перевод по фразам. Про омонимию у меня есть любимая шутка:

— Это ваш Ягуар у подъезда стоит?

— Да

— Я допью?

Статистический перевод по фразам — Phrase-based SMT

Взял за основу все принципы перевода по словам: статистика, перестановки и лексические хаки. Но для обучения он разбивал текст не только на слова, но и на целые фразы. Точнее, N-граммы или фраземы — пересекающиеся наборы из N слов подряд. Машина училась переводить устойчивые сочетания слов, что заметно улучшило точность.

Хитрость метода заключалась в том, что фразы не всегда были понятными нам со школы синтаксическими конструкциями. Как только в перевод пытался вмешиваться человек, знающий про лингвистику и строение предложений, качество перевода резко падало. Пионер компьютерной лингвистики Фредерик Йелинек однажды пошутил по этому поводу: «Каждый раз, когда из команды уходит лингвист, качество распознавания возрастает».

Помимо улучшения точности, перевод по фразам дал больше свободы в поиске двуязычных текстов для обучения. Для Word-based перевода было очень важно точное соответствие переводов, что исключало любые литературные или вольные переводы. Phrase-based прекрасно обучался даже на них. Многие даже начали парсить новостные сайты на разных языках и улучшать перевод текстами оттуда.

С 2006 года этот подход начали использовать все. Google, «Яндекс», Bing и другие качественные онлайн-переводчики работали именно как Phrase-based аж до самого 2016-го года. Каждый из вас может припомнить опыт, когда одно предложение Google переводил на отлично, литературно переставляя слова, а на другом начинал гнать полную околесицу. Такова особенность перевода по фразам.

Если старый добрый Rule-based подход стабильно давал хоть и ужасный, но предсказуемый результат, то статистические методы иногда удивляли и озадачивали. Можно вспомнить десяток шуток про Google Translate, когда он переводил «three hundred» как «300» и даже не смущался. Этот косяк назвали статистическими аномалиями.

Phrase-based перевод стал настолько популярным, что когда вы слышите «статистический машинный перевод», скорее всего, имеется в виду именно он. Вплоть до 2016 года во всех исследованиях Phrase-based перевод хвалебно называли the state-of-art. Тогда никто даже не подозревал, что в лаборатории Google уже завозят под это дело фуры с нейросетями, чтобы опять изменить наше представление о машинном переводе.

Статистический перевод на основе синтаксиса — Syntax-based SMT

Стоит кратенько упомянуть и этот метод. До прихода нейросетей про синтаксический перевод многие годы говорили как про «будущее переводчиков», но достичь успеха он так и не успел.

Адепты синтаксического перевода верили в объединение подходов SMT и старого трансферного перевода по правилам. Нужно научиться делать достаточно точный синтаксический разбор предложения — определять подлежащее, сказуемое, зависимые члены и вот это вот всё, а затем построить дерево.

Имея такое дерево, можно обучить машину правильно конвертировать фигуры одного языка в фигуры другого, выполняя остальной перевод по словам или фразам. Только делать это теперь не руками, а машинным обучением. В теории это решило бы проблему порядка слов навсегда.

Пример взят из Yamada and Knight и вот этих отличных слайдов

Трудность в том, что хоть человечество и считает проблему синтаксического разбора давно решённой (для многих языков есть готовые библиотеки), по факту он работает весьма плохо. Я лично много раз пытался использовать синтаксические деревья для задач сложнее вычленения подлежащего и сказуемого и каждый раз отказывался от этого в пользу других методов.

Если у вас был хоть один успешный опыт с ними, расскажите в комментариях.

Нейронный машинный перевод — Neural Machine Translation (NMT)

В 2014 году выходит статья с кратким описанием идеи применения нейросетей глубокого обучения к машинному переводу. В интернете её вообще никто не заметил, а вот в лабораториях Google начали активно копать. Спустя два года, в ноябре 2016 года, в блоге Google появился анонс, который и перевернул игру.

Идея была похожа на перенос стиля между фотографиями. Помните приложения вроде Prisma, которые обрабатывали фоточки в стиле известного художника? Там не было особой магии — нейросеть обучили распознавать картины художника, а потом «оторвали» последние слои, где она принимает решение. Получившиеся кишочки — промежуточное представление сети — и были той самой стилизованной картинкой. Она так видит, а нам красиво.

Если с помощью нейросети мы можем перенести стиль на фото, то что если попытаться подобным образом наложить другой язык на наш текст? Представить язык текста как тот самый «стиль художника», попытавшись его перенести, сохранив суть изображения (то есть суть текста).

Представьте, что я на словах описываю вам, как выглядит моя собака: средний размер, острый нос, большие уши, короткий хвост и гавкает постоянно. Я передаю вам набор характеристик собаки и при достаточно точном описании вы сможете даже нарисовать её, хотя никогда вживую не встречали.

Что если представить исходный текст как набор таких же характерных свойств? То есть закодировать его так, чтобы затем другая нейросеть — декодер — расшифровала его обратно в текст, но уже на другом языке. Мы специально обучим декодер знать только свой язык. Он и понятия не имеет, откуда взялись характеристики, но умеет выразить их, скажем, на испанском.

Продолжая аналогию: какая вам разница, чем рисовать описанную мной собаку — карандашами, акварелью или пальцем по грязи. Рисуете как умеете.

Ещё раз: первая нейросеть умеет только кодировать предложение в набор цифр-характеристик, а вторая — только декодировать их обратно в текст. Обе понятия не имеют друг о друге, каждая знает только свой язык. Ничего не напоминает? К нам вернулась идея интерлингвы. Та-дам.

Но как найти эти характеристики? С собакой всё понятно, у неё лапки и другие части тела, а с текстами как? Учёные 30 лет назад уже пытались скрафтить универсальный языковой код, это закончилось полным провалом.

Но у нас теперь есть диплёрнинг, который как раз этим и занимается. Главное отличие диплёрнинга от классических нейросетей как раз и было в том, что его сети обучаются находить характерные свойства объектов, не понимая их природы. При наличии достаточно большой нейросети и пары тысяч видеокарт в заначке, можно попытаться найти такие характеристики и в тексте.

Теоретически полученные нейросетями характеристики потом можно отдать лингвистам, и они откроют для себя много нового. «Яндекс» об этом как-то рассказывал.

Вопрос только в том, какой вид нейросети использовать в кодере и декодере. Для картинок отлично подходят сверхточные нейросети (CNN), потому что они работают с независимыми блоками пикселей. Но в тексте не бывает независимых блоков, каждое следующее слово зависит от предыдущих и даже последующих. Текст, речь и музыка всегда последовательны.

Для их обработки лучше подходят реккурентные нейросети (RNN), ведь они помнят предыдущий результат. В нашем случае это предыдущие слова в предложении. RNN сейчас применяют много где: распознавание речи в Siri (парсим последовательность звуков, где каждый зависит от предыдущего), подсказки слов на клавиатуре (запоминаем предыдущие и угадываем следующее), генерация музыки, даже чат-боты.

Для задротов вроде меня: на самом деле, архитектуры нейронных переводчиков сильно разнятся. Сначала исследователи использовали обычные RNN, потом перешли на двунаправленные — переводчик учитывал не только слова до нужного слова, но и после. Так было куда эффективнее. Потом вообще пошли по хардкору, используя многослойные RNN с LSTM-ячейками для долгого хранения контекста перевода.

За два года нейросети превзошли всё, что было придумано в переводе за последние 20 лет. Нейронный перевод делал на 50% меньше ошибок в порядке слов, на 17% меньше лексических и на 19% грамматических ошибок. Нейросети даже научались сами согласовывать род и падежи в разных языках, никто их этому не учил.

Самые заметные улучшения были там, где никогда не существовало прямого перевода. Методы статистического перевода всегда работали через английский язык. Если вы переводили, например, с русского на немецкий, машина сначала перегоняла текст в английский, а только потом переводила на немецкий. Двойные потери. Нейронному переводу это не нужно — подключай любой декодер и погнали. Впервые стало возможно напрямую переводить между языками, у которых не было ни одного общего словаря.

Google Translate (2016)

В 2016 году Google включила нейронный перевод девяти языков между собой, в 2017 году был добавлен и русский. Google разработала собственную систему под нехитрым названием Google Neural Machine Translation (GNMT), состоявшую аж из восьмислойного RNN на входе и на выходе и системы согласования контекста под названием Attention Model.

При обучении они не просто разбивали предложения по фразам и словам, они делили даже сами слова на части. Этим они пытались решить одну из главных проблем NMT — они беспомощны, когда слова нет в их словарном запасе.

Например, «Вастрик». Вряд ли кто-то обучал нейросеть переводить мой никнейм. В этом случае GMNT пытается собрать его и склеить как раз по этим частям. Хитро.

Hint: тот Google Translate, который переводит сайты в браузере, всё еще использует старый Phrase-based алгоритм. Почему-то Google его не обновляет, и на нём очень заметны отличия по сравнению с онлайн-версией.

В онлайн-версии Google Translate сделали ещё и механизм краудсорсинга переводов. Сейчас пользователи могут выбрать наиболее правильную, по их мнению, версию перевода, и, если так многим она понравится, Google будет всегда переводить эту фразу именно так, помечая специальным значком.

Это круто работает на коротких повседневных фразах вроде «пойдём на обед» или «буду ждать внизу». Google знает разговорный английский лучше меня. Переводчик Bing от Microsoft работает как полная копия Google Translate. А вот «Яндекс» от них отличается.

«Яндекс.Переводчик» (2017)

«Яндекс» запустил свой нейросетевой перевод в 2017 году. Главным отличием они заявили гибридность. Переводчик «Яндекса» переводит предложение сразу двумя методами — статистическим и нейросетевым, а потом с помощью их любимого алгоритма CatBoost находит наиболее подходящий.

Дело в том, что нейронный перевод плохо справляется с короткими фразами. Когда вам надо перевести словосочетание вроде «сиреневая бетономешалка», нейросети могут нафантазировать лишнего, а простой статистический перевод найдёт оба слова тупо, быстро и без проблем.

Других подробностей «Яндекс» нам не рассказывает, отбиваясь нетехническими пресс-релизами.

Судя по всему, Google тоже использует SMT для перевода слов и коротких словосочетаний. Они не упоминают это в статьях, но это очевидно по разнице между переводами коротких строк и длинных. Также SMT явно используется для показа статистики слова.

Заключение и будущее

Всех по-прежнему будоражит идея «Вавилонской Рыбки» — синхронного перевода речи на лету. Google делала шаг в этом направлении, когда анонсировала Pixel Buds, но на поверку всё оказалось плохо. Синхронный перевод на лету отличается от обычного, ведь нужно знать места, когда начать переводить, а когда сидеть и слушать. Нормального решения я так и не встречал.

Вот ещё одно не паханное поле на мой взгляд: всё обучение по прежнему упирается в ограниченный набор параллельных корпусов с текстами. Хвалёные глубоченные нейросети всё равно обучаются именно на параллельных текстах.

Мы не можем обучить нейросеть, не давая ей оригинала. Но человек-то может, начиная с определённого уровня знаний языка, пополнять словарный запас просто от чтения книг или статей, даже не переводя их на свой родной язык.

Если может человек, то и нейросеть в теории тоже. Встречал только один прототип, где придумали, как заставить обученную одному языку нейросеть бросить на другие тексты, чтобы набралась побольше опыта. Я бы и сам попробовал, но я глупенький. Так что на этом всё.

Полезные ссылки

#будущее#машинноеобучение

🔥 1 комментарий
Калькулятор расчета пеноблоков смотрите на этом ресурсе
Все о каркасном доме можно найти здесь http://stroidom-shop.ru
Как снять комнату в коммунальной квартире смотрите тут comintour.net

Категория: Избранные статьи.