Русский
Русский
English
Статистика
Реклама

Dataset

KotlinDL 0.2 Functional API, зоопарк моделей c ResNet и MobileNet, DSL для обработки изображений

25.05.2021 12:05:50 | Автор: admin

Представляем вам версию 0.2 библиотеки глубокого обучения KotlinDL.

KotlinDL 0.2 теперь доступен на Maven Central (до этого он лежал на bintray, но закатилось солнышко земли опенсорсной). Появилось столько всего нового: новые слои, специальный DSL для препроцессинга изображений, новые типы датасетов, зоопарк моделей с несколькими моделями из семейства ResNet, MobileNet и старой доброй моделью VGG (рабочая лошадка, впрочем).

В этой статье мы коснемся самых главных изменений релиза 0.2. Полный список изменений доступен по ссылке.

Functional API

Прошлая версия библиотеки позволяла описывать нейронные сети лишь при помощи Sequential API. Например, используя метод Sequential.of(..), вы могли легко описать модель как последовательность слоев и построить VGG-подобную модель.

Однако с 2014 года (эпохи взлета и расцвета подобных архитектур) много воды утекло, и было создано множество новых нейросетей. В частности, стандартным подходом стало использование так называемых остаточных нейросетей (Residual Neural Networks или ResNet), которые решают проблемы исчезающих градиентов (vanishing gradients) и, напротив, взрывающихся градиентов (exploding gradients) а значит, и проблемы деградации обучения нейросети. Подобные архитектуры невозможно описать в виде Sequential API их корректнее представлять в виде направленного ациклического графа (Directed Acyclic Graph). Для задания таких графов мы добавили в версии 0.2 новый Functional API, который позволяет нам описывать модели, подобные ResNet или MobileNet.

Ну что же, давайте построим некое подобие ResNet. Нейросеть будет обучаться на датасете FashionMnist (небольшие изображения модных вещей). Черно-белые изображения размером 28х28 отлично подойдут на старте работы с нейросетями.

val (train, test) = fashionMnist()val inputs = Input(28, 28, 1)val conv1 = Conv2D(32)(inputs)val conv2 = Conv2D(64)(conv1)val maxPool = MaxPool2D(poolSize = intArrayOf(1, 3, 3, 1),strides = intArrayOf(1, 3, 3, 1))(conv2)val conv3 = Conv2D(64)(maxPool)val conv4 = Conv2D(64)(conv3)val add1 = Add()(conv4, maxPool)val conv5 = Conv2D(64)(add1)val conv6 = Conv2D(64)(conv5)val add2 = Add()(conv6, add1)val conv7 = Conv2D(64)(add2)val globalAvgPool2D = GlobalAvgPool2D()(conv7)val dense1 = Dense(256)(globalAvgPool2D)val outputs = Dense(10, activation = Activations.Linear)(dense1)val model = Functional.fromOutput(outputs)model.use {it.compile(optimizer = Adam(),loss = Losses.SOFT_MAX_CROSS_ENTROPY_WITH_LOGITS,metric = Metrics.ACCURACY)it.summary()it.fit(dataset = train, epochs = 3, batchSize = 1000)val accuracy = it.evaluate(dataset = test, batchSize = 1000).metrics[Metrics.ACCURACY]println("Accuracy after: $accuracy")}

Перед вами вывод метода summary(), описывающий архитектуру только что созданной нами модели.

Некоторые не любят сухие отчеты и предпочитают диаграммы. В нашем случае диаграмма типична для всех представителей славного семейства ResNet.

Если вы знакомы с фреймворком Keras, то без особого труда сможете перенести модели, описанные при помощи Functional API, в Keras, используя KotlinDL.

Коллекция предварительно тренированных моделей ResNet и MobileNet

Начиная с релиза 0.2, в Kotlin DL появляется зоопарк моделей (или Model Zoo). По сути, это коллекция моделей с весами, полученными в ходе обучения на большом датасете изображений (ImageNet).

Зачем нужна такая коллекция моделей? Дело в том, что современные сверхточные нейросети могут иметь сотни слоев и миллионы параметров, обновляемых многократно в течении каждой итерации обучения. Тренировка моделей до приемлемого уровня точности (7080%) на таком большом датасете, как ImageNet, может занимать сотни и тысячи часов вычислительного времени большого кластера из видеокарт.

Зоопарк моделей позволяет вам пользоваться уже готовыми и натренированными моделями (вам не придется тренировать их с нуля каждый раз, когда они вам нужны). Вы можете использовать такую модель непосредственно для предсказаний. Также вы можете применить ее для дотренировки части модели на небольшой порции входных данных это весьма распространненная техника при использовании переноса обучения (Transfer Learning). Это может занять десятки минут на одной видеокарте (или даже центральном процессоре) вместо сотен часов на большом кластере.

Доступны следующие модели:

  • VGG16

  • VGG19

  • ResNet50

  • ResNet101

  • ResNet152

  • ResNet50v2

  • ResNet101v2

  • ResNet152v2

  • MobileNet

  • MobileNetv2

Для каждой модели из этого списка доступны функции загрузки конфигурации модели в JSON-формате и весов в формате .h5. Также для каждой модели можно использовать специальный препроцессинг, применявшийся для ее обучения на датасете ImageNet.

Ниже вы видите пример загрузки одной из таких моделей (ResNet50):

// specify the model type to be loaded, ResNet50, for exampleval loader =ModelZoo(commonModelDirectory = File("cache/pretrainedModels"), modelType = ModelType.ResNet_50)// obtain the model configurationval model = loader.loadModel() as Functional// load class labels (from ImageNet dataset in ResNet50 case)val imageNetClassLabels = loader.loadClassLabels()// load weights if required (for Transfer Learning purposes)val hdfFile = loader.loadWeights()

Ну что же, теперь у вас есть сама модель и веса вы можете использовать их по вашему усмотрению.

Внимание! К изображениям, которые вы подаете на вход модели для предсказаний, необходимо применять специальный препроцессинг, о котором мы говорили ранее. Иначе вы получите неверные результаты. Для вызова препроцессинга используйте функцию preprocessInput.

Если вам не нужны предобученные веса, но вы не хотите описывать многослойные модели а-ля VGG или ResNet с нуля, у вас есть два пути: а) просто загрузить конфигурацию модели либо б) взять за основу полный код конструирования модели, написанный на Kotlin, он доступен для каждой из моделей через вызов функции высшего порядка, лежащей в пакете org.jetbrains.kotlinx.dl.api.core.model.

Ниже мы приводим пример использования функции, строящей облегченную версию ResNet50:

val model = resnet50Light(imageSize = 28,numberOfClasses = 10,numberOfChannels = 1,lastLayerActivation = Activations.Linear)

Если вы хотите узнать больше о переносе обучения и использовании зоопарка моделей, советуем этот туториал: вы увидите, как загружается модель VGG19, затем у нее удаляется последний слой, добавляются новые Dense-слои, после чего их веса инициализируются и дообучаются на небольшом датасете, состоящем из изображений кошек и собак.

DSL для предобработки изображений

Python-разработчикам предлагается огромное количество библиотек визуализации и предобработки изображений, музыки и видео. Разработчикам экосистемы языков программирования JVM повезло меньше.

Большинство библиотек для предобработки изображений, найденные на просторах Github и имеющие разную степень заброшенности, так или иначе используют класс BufferedImage, оборачивая его более понятным и согласованным API. Мы решили упростить жизнь Kotlin-разработчиков, предложив им простой DSL, построенный на лямбда-выражениях и объектах-приемниках.

На данный момент доступны следующие функции преобразования изображений:

  • Load

  • Crop

  • Resize

  • Rotate

  • Rescale

  • Sharpen

  • Save

val preprocessing: Preprocessing = preprocess {   transformImage {       load {           pathToData = imageDirectory           imageShape = ImageShape(224, 224, 3)           colorMode = ColorOrder.BGR       }       rotate {           degrees = 30f       }       crop {           left = 12           right = 12           top = 12           bottom = 12       }       resize {           outputWidth = 400           outputHeight = 400           interpolation = InterpolationType.NEAREST       }   }   transformTensor {       rescale {           scalingCoefficient = 255f       }   }}

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

Если, экспериментируя с DSL, вы поймете, что некоторых функций вам не хватает, не стесняйтесь написать об этом в наш баг-трекер.

Новые слои

В релизе 0.2 появилось много новых слоев. В основном, это обусловлено тем, что они используются в архитектурах ResNet и MobileNet:

  • BatchNorm

  • ActivationLayer

  • DepthwiseConv2D

  • SeparableConv2D

  • Merge (Add, Subtract, Multiply, Average, Concatenate, Maximum, Minimum)

  • GlobalAvgPool2D

  • Cropping2D

  • Reshape

  • ZeroPadding2D*

* Спасибо Anton Kosyakov за имплементацию нетривиального ZeroPadding2D!

Кстати, если вы хотите добавить новый слой, вы можете самостоятельно реализовать его и создать пул-реквест. Список слоев, которые мы хотели бы включить в релиз 0.3, представлен набором тикетов в баг-трекере с пометкой good first issue и может быть использован вами как точка входа в проект.

Dataset API и парочка наследников: OnHeapDataset & OnFlyDataset

Типичным способом прогона данных через нейросеть в режиме прямого распространения (forward mode) является последовательная загрузка батчей в оперативную память, контролируемую языком, а затем в область нативной памяти, контролируемую вычислительным графом модели TensorFlow.

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

Этот метод хорош, когда оперативной памяти мало, а данных много. Но что, если оперативной памяти более чем достаточно? Это не такой уж редкий случай для задач переноса обучения: датасеты для дообучения могут быть не такими большими, как при тренировке моделей. Также можно получить некоторый прирост в скорости за счет того, что препроцессинг будет применен лишь один раз на этапе формирования датасета, а не при каждой загрузке батча. Если у вас достаточно оперативной памяти, используйте OnHeapDataset. Он будет держать все данные в оперативной памяти не нужно будет повторно считывать их с диска на каждой эпохе.

Набор встроенных датасетов

Если вы только начинаете путешествие в удивительный мир глубокого обучения, мы настоятельно рекомендуем вам строить и запускать ваши первые нейросети на широко известных датасетах, таких как MNIST (набор рукописных цифр), FashionMNIST(набор изображений модных вещей от компании Zalando), Cifar10 (подмножество ImageNet, насчитывающее 50 000 изображений) или коллекцию изображений кошек и собак со знаменитого соревнования Kaggle (по 25 000 изображений каждого класса различных размеров).

Все эти датасеты, как и модели из зоопарка моделей, вы можете загрузить в папку на вашем диске при помощи функций высшего порядка, таких как mnist() и fashionMnist(). Если датасет уже был загружен, заново по сети он грузиться не будет, а будет взят с диска.

Как добавить KotlinDL в проект

Чтобы начать использовать KotlinDL в вашем проекте, просто добавьте дополнительную зависимость в файл build.gradle:

repositories {    mavenCentral()}dependencies {    implementation 'org.jetbrains.kotlinx:kotlin-deeplearning-api:0.2.0'}

KotlinDL можно использовать в Java-проектах, даже если у вас нет ни капли Kotlin-кода. Здесь вы найдете пример построения и тренировки сверточной сети, полностью написанный на Java.

Если вы думаете, что в вашем проекте будет полезен Java API, напишите нам об этом или создайте PR.

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

Мы надеемся, что вам понравилась наша статья и новые возможности KotlinDL.

Хотите узнать больше о проекте? Предлагаем ознакомиться с Readme или со страничкой проекта на GitHub. А этот туториал поможет вам создать вашу первую нейросеть на Kotlin.

Если вам интересно, как устроен KotlinDL, как он появился и в каком направлении развивается, почему он так похож на Keras, и планируется ли поддержка PyTorch, посмотрите свежее видео от Алексея Зиновьева.

Также мы ждем вас в Slack-канале #kotlindl (инвайт можно получить тут). В нем вы можете задавать вопросы, участвовать в дискуссиях и первыми получать информацию о превью-релизах и новых моделях в зоопарке моделей.

Ваша обратная связь, ваши описания багов и краш-репорты, идеи и комментарии все это очень важно для нас. Мы ждем новых пользователей и контрибьюторов, как начинающих, так и опытных исследователей всех, кому интересны Deep Learning и Data Science на Kotlin, Java и Scala!

Подробнее..

Event2Mind для русского языка. Как мы обучили модель читать между строк и понимать намерения собеседника

18.06.2020 18:21:58 | Автор: admin
Умение модели распознавать намерения собеседника, то есть понимать зачем человек совершил то или иное действие, применимо в большом числе прикладных NLP-задач. К примеру, чат-ботам, голосовым помощникам и другим диалоговые системам это позволит эмоционально реагировать на высказывания собеседника, проявлять понимание, сочувствие и другие эмоции. Кроме того, задача распознавания намерения это еще один шаг на пути к пониманию человеческой речи (human understanding).



Уже было предпринято несколько попыток решить данную задачу в той или иной форме. Например, на NLP-progress публикуются последние достижения в области commonsense reasoning. Слабость большинства существующих моделей заключается в том, что в их основе лежит supervised подход, то есть им требуются большие размеченные датасеты для обучения. А в силу специфичности задачи разметка часто бывает весьма нестандартной и достаточно сложной.

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

В этом посте мы расскажем, как мы создали датасет для задачи Common Sense Reasoning в одной из ее возможных формулировок, предложенной в статье event2mind, а также адаптировали английскую модель event2mind от AllenNLP для русского языка. Для начала немного расскажем, что же из себя представляет задача Common Sense Reasoning.

На самом деле, правильнее было бы рассматривать это как целое направление задач, направленных на распознавание намерений и эмоций действующего лица. Единой формулировки у нее нет, и в данном посте мы возьмем за основу вот такой ее вариант, предложенный авторами event2mind: по короткому тексту в свободной форме, содержащему некоторое действие или событие (например, PersonX eats breakfast in the morning), определить намерения субъекта (X wants to satisfy hunger), его эмоции/реакции (X feels satiated, full) и возможные эмоции/реакции других участников события, если таковые присутствуют. Рисунок 1 это наглядно иллюстрирует.

Рисунок 1. Задача Commonsense Reasoning по короткому тексту-событию определить намерения, эмоции/реакции субъекта и эмоции/реакции окружающих


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

Данные, данные и еще раз данные


Итак, нашей задачей было собрать корпус размеченных текстов в свободной форме в формате, пригодном для обучения event2mind. Для простоты дальше мы будем называть такие короткие тексты просто событиями. При этом мы старались максимально расширить common sense reasoning кругозор модели, собрав события на самые разные темы из повседневной жизни.

Часть первая. Crowdsourced corpus


На первом этапе нам предстояло собрать достаточное количество сырых событий для последующей разметки. За основу мы взяли три источника данных:
  1. Короткие посерийные описания сериалов и мыльных опер. Мы вручную отобрали 50 сериалов с сюжетами из повседневной жизни, такие как Друзья, Секс в большом городе, Санта-Барбара, Универ, Кухня и другие. При этом мы старались выбирать сериалы о повседневной жизни с сюжетами на общие темы. Фантастика или профессиональные сериалы нам не подходили, так как они содержат очень много специальной лексики, и события там из своей специфичной области. Вы представляете, что может выучить модель, обученная на Докторе Хаусе или Звездном пути? Еще начнет подозревать у всех волчанку и сыпать рассказами о сражениях с инопланетянами.
  2. Краткие содержания книг. Суммарно нам удалось набрать краткие содержания 1512 книг.
  3. Тексты из SynTagRus, который является частью Русского Национального корпуса и содержит художественные тексты вместе с новостями.


На следующем шаге мы извлекли события из собранных текстов. События для тренировки event2mind можно определить как комбинацию глагольного предиката с входящими в составляющую глагола аргументами. Для поиска подобных паттернов был использован синтаксический парсер UdPipe, с помощью которого мы выделяли в текстах паттерны вида глагол + зависимые слова в синтаксическом дереве, как например на рисунке 2, которые удовлетворяли одному из следующих правил:

  • nsubj + root + obj
  • nsubj + root + iobj
  • nsubj + advmod + root
  • nsubj + root + case + obl
  • etc.


Рисунок 2. Синтаксические паттерны, использованные для извлечения событий из текстов



Отобранные события обезличиваются. По аналогии с оригинальным event2mind все действующие лица и именованные сущности были заменены на единообразные PersonX, а также PersonY и PersonZ, если в предложении упоминается более одного действующего лица. Для распознавания именованных сущностей (Named Entity Recognition) и дальнейшей замены мы вновь воспользовались UdPipe: в событиях, которые отвечают паттернам выше мы деперсонилизировали токены, помеченные тегами PROPN или PRONOUN. В завершении мы исключили события, которые не содержат одушевленных субъектов. Например, по этому критерию было отсеяно предложение Идет дождь. В итоге в корпус вошли только события с одушевленными именованными сущностями (person named entities).

После деперсонализации и фильтрации мы воспользовались частотным анализом и расстоянием Левенштейна для отобора наиболее распространенных событий и фильтрации нестандартных примеров, которые встретились лишь единожды. Во-первых, мы взяли все события, которые встретились в первоначальной выборке больше одного раза. Для оставшейся части данных мы посчитали попарные расстояния Левенштейна $L(phrase_1,phrase_2)$, ), отобрали пары, для которых оно не превосходило 5 и из каждой пары взяли более короткое предложение. При таком методе мы руководствовались следующим соображением: если для пары событий их расстояние Левенштейна мало (в данном случае порог 5), то эти предложения отличаются весьма незначительно, например, в роде глагола или прилагательного. Фактически это вариации одного и того же события. А более короткое предложения из пары мы выбирали потому, что оно скорее будет содержать начальные формы слов (они чаще короче, хотя и не всегда).

После сбора данных события предстояло разметить, выделив в них намерения PersonX, его эмоции/реакции, а также эмоции/реакции PersonY и PersonZ, если таковые присутствуют. Для этого мы создали задание в Яндекс.Толоке. Пример из него вы можете видеть на рисунке 3. Для каждого события мы спрашивали разметчиков:

  • содержит ли оно осмысленное событие;
  • можно ли по тексту события понять намерения действующего лица;
  • можно ли по событию понять эмоции/реакцию действующего лица;
  • может ли это событие вызвать реакцию окружающий.


Рисунок 3. Пример задания из Яндекс.Толоки



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

Тут стоит оговориться, что поскольку переведенные данные получились достаточно сырыми, то обученная на них модель оказалась слабой. До полноценной модели она не дотягивала, но в некоторых случаях ей достаточно точно удавалось угадывать эмоции и намерения субъектов.

В итоге нам удалось собрать 6756 событий на различные повседневные темы.

Часть 2. Translated English corpus


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

Дело в том, что разметка подобного датасета трудоемкое дело, требующее большого количества ресурсов, денег и средств. У нас просто не было возможности разметить корпус, по размерам сопоставимый с английским, который состоит из 46 тысяч примеров. Поскольку собранный на русском датасет оказался меньшего размера, мы решили оценить, хватит ли такого объема данных для обучения. Для этого мы обучили английскую модель на частях оригинального корпуса и измерили, как меняется качество в зависимости от размера обучающего датасета. Результаты приведены в таблице. Качество для намерений (intent) и эмоций/реакций (react) оценивалось, по аналогии с оригинальной статьей, по метрике recall@10 на валидации. recall@10 отражает долю случаев, когда истинный ответ golden standard попадает в топ-10 предсказаний модели. Метрика меняется от 0 до 1, чем больше, тем лучше.

Таблица 1. Зависимость качества английской модели от размера корпуса для обучения



Сразу можно сказать, что 5000 примеров недостаточно для полноценного обучения модели. Однако уже при 30000 примеров, loss и recall практически не отличаются от результатов на полном объеме данных. Получается, что размеченных нами 7000 примеров не хватает для обучения модели и необходимо каким-то способом увеличить размер обучающей выборки.

Для этого мы подготовили дополнительный корпус, полученный из английского с помощью автоматического перевода Google Переводчиком. Как уже отмечалось выше, при автоматическом переводе всего корпуса некоторые переводы оказывались некорректными или полностью теряли смысл. Поэтому мы отобрали ту часть английских данных, которая переводилась наиболее адекватно. Изначально английский корпус собран из нескольких источников: ROC Story training set, the GoogleSyntactic N-grams, the Spinn3r corpus и idioms. При этом предложения из некоторых источников оказались проще для перевода, чем из других. Например, адекватный перевод идиом без ручной правки оказался не под силу компьютеру. Поэтому мы взяли только примеры из ROC-story. По результатам оригинальной статьи (см. таблицу 2), у этого источника коэффициент согласованности аннотаторов (Cohen's kappa coefficient), равный 0.57. А это, скорее всего, свидетельствует о том, что события оттуда проще для понимания и разметки, а значит меньше подвержены ошибкам при переводе.

Таблица 2 Данные и Cohen's kappa coefficient для разных источников в английском корпусе


После этого мы отфильтровали отобранные данные, удалили оттуда примеры, в которых после перевода остались английские слова и примеры, которые были переведены некорректно. Оставшаяся часть была отредактирована редакторами.

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

В итоге нам удалось набрать 23409 переведенных событий, а объем объединенного корпуса с учетом размеченной русской части составил 30165. Этого, как мы выяснили во время экспериментов, должно было хватить для обучения русской модели.

А теперь к экспериментам!


Итак, данные собраны, пора переходить к обучению модели и экспериментам. Модель event2mind представляет собой нейросетевую архитектуру вида encoder-decoder с одним энкодером и тремя декодарами для каждого вида предсказаний (см. рисунок 4): намерение субъекта, его эмоции/реакции и эмоции/реакции других участников события, если таковые имеются (subjects intent, subjectss reaction и others events participants reactions). Исходные предложения изначально векторизуются с помощью одного из методов векторных представлений слов (например, word2vec или fasttext) и кодируются с помощью энкодера в вектор $h^E\in \mathbb{R}^H$. А затем с помощью трех RNN декодеров генерируются предсказания. Благодаря этому модель может генерировать ответы даже для намерений и реакций, которые она до этого не видела.

Рисунок 4. Архитектура модели event2mind


Для экспериментов мы использовали объединенный корпус для русского языка, размеченную и переведенную части. А чтобы сделать распределение русских и переведенных примеров более равномерным, мы дополнительно перемешали данные. Отметим, что мы также попробовали обучить модель только на размеченных данных, но из-за маленького объема датасета, она показала очень плохие результаты. Мы протестировали различные слои в энкодере LSTM и GRU, а также попробовали различные векторные представления fasttext и word2vec с RusVectores. Результаты приведены в таблице 3, результаты по intentам и reactам, как и ранее считались по метрике recall@10.

Таблица 3. результаты моделей для русского языка, intent и react оценивались по recall@10


Итак, какие выводы можно сделать из результатов экспериментов? Во-первых, word2vec embeddings оказались немного лучше, чем fasttext. При этом fasttext embeddings, обученные на ruscorpora показали себя лучше обученных на araneum. Во-вторых, можно отметить, что при использовании word2vec, GRU в энкодере оказывается лучше LSTM. И наконец, лучшая модель (areneum word2vec + GRU) практически повторяет результаты для английского языка.

И напоследок посмотрим на реальные примеры!





Весьма неплохо! Намерения выглядят весьма правдоподобно и действительно отражают какие-то общечеловеческие понятия и знания. А вот с эмоциями/реакциями модель справилась несколько хуже, они получились более примитивными и однообразными. Возможно, это связано с тем, что эмоции зависят от большего объема текста и короткого текста-события недостаточно, чтобы правильно его определить.

Вместо заключения


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



Такой большой проект стал возможен, только благодаря совместным усилиям нашей команды. В адаптации event2mind для русского языка также принимали участие alenusch и onetwotrickster.
Подробнее..

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

30.06.2020 18:10:31 | Автор: admin

Привет, Хабр! Как известно, топливом для машинного обучения являются наборы данных. В качестве источников для получения датасетов, которыми люди обычно пользуются и которые у всех на слуху, являются такие сайты как Kaggle, ImageNet, Google Dataset Search и Visual Genom, но довольно редко встречаю людей, которые для поиска данных используют такие сайты как Bing Image Search и Instagram. Поэтому в этой статье я покажу как легко получить данные с этих источников, написав две небольшие программы на Python.


Bing Image Search


Первое, что нужно сделать это перейти по ссылке нажать кнопку Get API Key и зарегистрироваться с помощью любой из предложенных социальных сетей(Microsoft, Facebook, LinkedIn или GitHub). После того, как процесс регистрации завершится вас перенаправят на страницу Your APIs, которая должна выглядеть подобным образом( то, что замазано, это и есть ваши API ключи) :


1


Переходим к написанию кода. Импортируем необходимые библиотеки :


from requests import exceptionsimport requestsimport cv2import os

Дальше нужно указать некоторые параметры: API ключ( нужно выбрать из двух предложенных ключей один), указать условия поиска, максимальное количество изображений на запрос, а также установим конечный URL :


subscription_key = "YOUR_API_KEY"search_terms = ['girl', 'man']number_of_images_per_request = 100search_url = "https://api.cognitive.microsoft.com/bing/v7.0/images/search"

Теперь напишем три небольшие функции, которые:
1) Создают для каждого условия поиска отдельную папку :


def create_folder(name_folder):    path = os.path.join(name_folder)    if not os.path.exists(path):        os.makedirs(path)        print('------------------------------')        print("create folder with path {0}".format(path))        print('------------------------------')    else:        print('------------------------------')        print("folder exists {0}".format(path))        print('------------------------------')        return path

2) Возвращает содержимое ответа сервера в JSON :


def get_results():    search = requests.get(search_url, headers=headers,                           params=params)    search.raise_for_status()    return search.json()

3) Записывает изображения на диск :


def write_image(photo):    r = requests.get(v["contentUrl"], timeout=25)    f = open(photo, "wb")    f.write(r.content)    f.close()

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


for category in search_terms:    folder = create_folder(category)    headers = {"Ocp-Apim-Subscription-Key": subscription_key}    params = {"q": category, "offset": 0,              "count": number_of_images_per_request}    results = get_results()    total = 0    for offset in range(0, results["totalEstimatedMatches"],                        number_of_images_per_request):        params["offset"] = offset        results = get_results()        for v in results["value"]:            try:                ext = v["contentUrl"][v["contentUrl"].                                          rfind("."):]                photo = os.path.join(category, "{}{}".                                     format('{}'.format(category)                                     + str(total).zfill(6), ext))                write_image(photo)                print("saving: {}".format(photo))                image = cv2.imread(photo)                if image is None:                    print("deleting: {}".format(photo))                    os.remove(photo)                    continue                total += 1            except Exception as e:                if type(e) in EXCEPTIONS:                    continue

Instagram


Импортируем библиотеки:


from selenium import webdriverfrom time import sleepimport pyautoguifrom bs4 import BeautifulSoupimport requestsimport shutil

Как вы можете видеть, я использую библиотеку selenium, поэтому нужно скачать geckodriver. В инстаграме поиск изображений будем осуществлять по хэштегу, допустим, возьмём хэштег #bird. По данному хэштегу можно найти около 26млн публикаций. Копируем ссылку, которая сформировалась в результате запроса и путь к geckodriver, и вставляем это соответственно в две строчки, которые представлены ниже:


browser=webdriver.Firefox(executable_path='/path/to/geckodriver')browser.get('https://www.instagram.com/explore/tags/bird/')

Дальше напишем 6 функций, которые:
1) Входит в инстаграм аккаунт. В строчках login.send_keys(' ') и password.send_keys(' ') необходимо вставить свой логин и пароль соответственно:


def enter_in_account():    button_enter = browser.find_element_by_xpath("//*[@class='sqdOP  L3NKy   y3zKF     ']")    button_enter.click()    sleep(2)    login = browser.find_element_by_xpath("//*[@class='_2hvTZ pexuQ zyHYP']")    login.send_keys('')    sleep(1)    password = browser.find_element_by_xpath("//*[@class='_2hvTZ pexuQ zyHYP']")    password.send_keys('')    enter = browser.find_element_by_xpath(        "//*[@class='                    Igw0E     IwRSH      eGOV_         _4EzTm                                                                                                              ']")    enter.click()    sleep(4)    not_now_button = browser.find_element_by_xpath("//*[@class='sqdOP yWX7d    y3zKF     ']")    not_now_button.click()    sleep(2)

2) Находит первый пост и нажимаем на него:


def find_first_post():    sleep(3)    pyautogui.moveTo(450, 800, duration=0.5)    pyautogui.click()

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


3) Получаем ссылку на публикацию и нажимаем на кнопку далее:


def get_url():    sleep(0.5)    pyautogui.moveTo(1740, 640, duration=0.5)    pyautogui.click()    return browser.current_url

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


4)Получаем html-код исходной страницы:


def get_html(url):    r = requests.get(url)    return r.text

5) Получаем URL изображения:


def get_src(html):    soup = BeautifulSoup(html, 'lxml')    src = soup.find('meta', property="og:image")    return src['content']

6) Скачиваем и сохраняем текущее изображение. В переменной filename нужно указать по какому пути будет сохраняться ваше изображение:


def download_image(image_name, image_url):    filename = 'bird/bird{}.jpg'.format(image_name)    r = requests.get(image_url, stream=True)    if r.status_code == 200:        r.raw.decode_content = True        with open(filename, 'wb') as f:            shutil.copyfileobj(r.raw, f)        print('Image sucessfully Downloaded')    else:        print('Image Couldn\'t be retreived')

Заключение


В заключении хотелось бы сказать про недостаток источников и реализации. Что касается самих ресурсов, то изображений с них можно собрать большое количество, но эти данные придётся сортировать, так как изображения не всегда подходят под те критерии поиска, которые вы задали. Что касается реализации, то в получении данных с инстаграма была задействована библиотека pyautogui, которая эмулирует действия пользователя, в результате чего, при выполнении программы вы не сможете задействовать ваш компьютер для решения других задач. Если будут предложения, как написать код лучше, прошу писать в комментарии.
Что касается написания кода, то всё было сделано на Ubuntu 18.04. Исходный код выложил на GitHub .

Подробнее..

Перевод Как переписать SQL-запросы на Python с помощью Pandas

31.07.2020 18:06:20 | Автор: admin
В этой статье June Tao Ching рассказал, как с помощью Pandas добиться на Python такого же результата, как в SQL-запросах. Перед вами перевод, а оригинал вы можете найти в блоге towardsdatascience.com.

image
Фото с сайта Unsplash. Автор: Hitesh Choudhary

Получение такого же результата на Python, как и при SQL-запросе


Часто при работе над одним проектом нам приходится переключаться между SQL и Python. При этом некоторые из нас знакомы с управлением данными в SQL-запросах, но не на Python, что мешает нашей эффективности и производительности. На самом деле, используя Pandas, можно добиться на Python такого же результата, как в SQL-запросах.

Начало работы


Нужно установить пакет Pandas, если его нет.

conda install pandas

Мы будем использовать знаменитый Датасет Титаник от Kaggle.

После установки пакета и загрузки данных нам необходимо импортировать их в наше окружение Python.

image

Для хранения данных мы будем использовать DataFrame. Управлять этой структурой данных нам помогут различные функции Pandas.

SELECT, DISTINCT, COUNT, LIMIT


Начнем с простых SQL-запросов, которые мы часто используем.

image

titanic_df["age"].unique() вернет массив уникальных значений, поэтому нам придется использовать len(), чтобы посчитать их количество.

SELECT, WHERE, OR, AND, IN (SELECT с условиями)


После первой части вы узнали, как простыми способами исследовать DataFrame. Теперь попробуем сделать это с некоторыми условиями (это оператор WHERE в SQL).

image

Если мы хотим выбрать только определенные столбцы из DataFrame, мы можем сделать это с помощью дополнительной пары квадратных скобок.

Примечание: если вы выбираете несколько столбцов, вам нужно поместить массив ["name","age"] внутри квадратных скобок.

isin() работает точно так же, как IN в SQL-запросах. Чтобы использовать NOT IN, на Python нам нужно использовать отрицание (~).

GROUP BY, ORDER BY, COUNT


GROUP BY и ORDER BY также являются популярными SQL-операторами при исследовании данных. А теперь давайте попробуем использовать их на Python.

image

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

Метод sum() выдаст суммы для каждого из столбцов в DataFrame, которые могут быть численно агрегированы. Если нам нужен только определенный столбец, то нужно указать имя столбца, используя квадратные скобки.

MIN, MAX, MEAN, MEDIAN


И наконец, давайте попробуем некоторые стандартные статистические функции, которые важны при исследовании данных.

image

SQL не содержит операторов, возвращающих медианное значение, поэтому для получения медианного значения столбца с информацией о возрасте мы используем BigQuery APPROX_QUANTILES

В Pandas метод агрегации .agg() также поддерживает другие функции, например sum.

Теперь вы научились переписывать SQL-запросы на Python с помощью Pandas. Надеюсь, эта статья будет вам полезна.

Весь код можно найти в моем репозитории Github.

Спасибо за внимание!
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru