Видео проигрыватель загружается.Воспроизвести видеоВоспроизвестиБез звукаТекущее время 0:00/Продолжительность 5:32Загрузка: 0.00%0:00Тип потока ОНЛАЙНSeek to live, currently behind liveОНЛАЙНОставшееся время -5:32 1xСкорость воспроизведения2x1.75x1.5x1.25x1x, выбрано0.75x0.5xГлавыГлавыОписанияОтключить описания, выбраноСубтитрынастройки субтитров, откроется диалог настройки субтитровСубтитры выкл., выбраноЗвуковая дорожкаPicture-in-PictureПолноэкранный режимThis is a modal window.Начало диалоговго окна. Кнопка Escape закроет или отменит окноТекстColorБелыйЧерныйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачностьПолупрозрачныйФонColorЧерныйБелыйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачностьПолупрозрачныйПрозрачныйОкноColorЧерныйБелыйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачныйПолупрозрачныйПрозрачностьРазмер шрифта50%75%100%125%150%175%200%300%400%Стиль края текстаНичегоПоднятыйПониженныйОдинаковыйТеньШрифтПропорциональный без засечекМоноширинный без засечекПропорциональный с засечкамиМоноширинный с засечкамиСлучайныйПисьменныйМалые прописныеСбросить сбросить все найстройки по умолчаниюГотовоЗакрыть модальное окноКонец диалогового окна.
В остальном, процедура заполнения тензоров достаточно простая — мы просто итерируемся по всем предложениям, по всем токенам в предложении, и для каждого токена кладём в соответствующую ячейку тензора меток идентификатор метки, а также кладём в соответствующую ячейку входного тензора идентификатор очередного символа. Ну что ж, тензоры мы построили, положили их датасет, давайте теперь посмотрим, как данные будут выглядеть для нейросети во время обучения. Для этого давайте выведем на экран фрагмент тензора, представляющего второе предложение из обучающей выборки — первые пять слов этого предложения. Мы видим прямоугольный тензор, каждая строчка этого тензора представляет один токен и содержит номера символов, которые в этом токене используются, в том порядке, в котором они встречались в самом токене. Обратить внимание здесь нужно на две вещи — первая: это стартовый нолик, он нам нужен для того, чтобы указать нейросети, что это — начало токена. Всё, что после последнего символа — заполняется нулями. Количество значимых элементов в каждой такой строчке у нас отличается. У нас есть короткие и длинные токены. Так выглядит входной тензор. Давайте теперь посмотрим, как выглядит тензор меток. Целевой тензор для этого же предложения — мы выбрали второе предложение из обучающей выборки, и это уже не двухмерный тензор, это одномерный тензор, то есть это просто список чисел, каждое число представляет номер тэга соответствующего токена. Для первого токена из этого предложения мы должны будем предсказать класс номер "8", для 2 — класс номер "1". Для токенов фиктивных, ненастоящих, мы всегда должны будем предсказывать "0". Напомню, что фиктивные токены у нас не являются частью исходного предложения, они используют для того, чтобы выровнять длины всех предложений и иметь возможность упаковывать предложения разной длины в прямоугольный тензор и обрабатывать в пакетном режиме в нейросети. Это нужно для того, чтобы эффективно использовать возможности современных вычислителей — видеокарт. Перед тем, как перейти непосредственно к решению нашей задачи, давайте определим вспомогательный нейросетевой модуль. Он состоит из свёрток, функции активации и дропаута. Давайте сначала посмотрим на функцию "forward", то есть на то, как этот модуль работает. Здесь мы видим, что в основе модуля лежит набор блоков — одинаковых блоков. Давайте попробуем изобразить этот модуль графически. У нас в начале есть "x", он подаётся в некий блок "layer 1", затем выход "layer 1" приплюсовывается к его же входу. Это всё подаётся в следующий — такой же блок "layer 2" и снова приплюсовывается... наверное, вам это что-то напоминает. Это простенький ResNet. Зачем это нужно? Использование вот этих связей (skip connection) ускоряет сходимость, а также позволяет нам сделать нейросеть более глубокой. Другими словами, без "skip connection" мы можем сделать нейросеть максимум из 5...9 блоков глубиной, но, используя "skip connection", мы можем делать нейросеть произвольной глубины, она по-прежнему будет обучаться. Давайте теперь посмотрим, как же устроен каждый из вот этих блоков. Каждый из этих блоков реализуется с помощью модуля pytorch "sequential" — это базовый модуль, который берёт список других модулей и выполняет их по-очереди, передавая результат первого во второй, из второго в третий, и так далее. В этом блоке первый слой — это свёрточный слой. Это одномерные свёртки — для текстов чаще всего используются одномерные свёртки. По умолчанию, мы говорим, что размер ядра равен 3. При этом, свёрточный слой не меняет количества каналов — он принимает одно и то же число каналов и возвращает одно и то же число каналов. Кроме того, здесь мы используем padding. Мы просим, чтобы размерность тензора вообще никак не менялась, то есть по умолчанию при нулевом padding свёртки немного сжимают тензор по пространственному измерению. Здесь мы просим, чтобы размерность тензора оставалась прежней. Для этого, перед тем, как применять свёртки, нужно добавить какое-то количество нулей в начало и в конец тензора. Реализацию свёрточного модуля мы рассмотрим попозже. Второй слой в нашем блоке — это dropout. Он нужен для того, чтобы нейросеть меньше переобучалась. В режиме обучения dropout зануляет случайные ячейки тензора. Когда нейросеть обучена, dropout ничего не делает. Третий слой нашего блока — это функция активации. Здесь мы используем Leaky ReLU, часто это — неплохой выбор. Таким образом, мы определили достаточно универсальный свёрточный модуль, который можно использовать в абсолютно разных ситуациях и, в рамках этого семинара, мы будем использовать его, как минимум, в двух разных случаях. Давайте теперь перейдём к конкретным архитектурам для определения частей речи токенов и попробуем что-нибудь уже обучить!

К сожалению, у нас пока нет статистики ответов на данный вопрос, но мы работаем над этим.