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

Блог компании open data science

Пора избавляться от мышки или Hand Pose Estimation на базе LiDAR за 30 минут

12.01.2021 14:15:46 | Автор: admin
image

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

Предлагаю начать с посмотра коротенького видео, на котором видно, как можно за пару вечеров накидать простейшее управления курсором мышки на основе Object Detection, Hand Pose Estimation и камеры Intel Realsense L515. Конечно, оно далеко от идеала, но кажется, что осталось совсем немного подтянуть технологии и появятся принципиально новые способы управлять устройствами.



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

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

Основная идея это двигать мышь, передвигая не всю руку, а только указательный палец, что позволит не отрывая рук от клавиатуры, бегать по меню, нажимать кнопки и в совокупности с горячими клавишами превратиться в настоящего клавиатурного ninja! А что будет если добавить жесты пролистывания или скоролла? Думаю будет бомба! Но до этого момента нам еще придётся подождать пару-тройку лет)

Начнём собирать наш протитип манипулятора будущего



Что понадобится:
1. Камера с LiDAR Intel Realsense L515.
2. Умение программировать на python
3. Совсем чуть-чуть вспомнить школьную математику
4. Крепление для камеры на монитор ака штатив

Крепим камеру на шатив с алиэкспресс, он оказался очень удобный, лёгкий и дешевый =)
image
image

Разбираемся, как и на чём делать прототип



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

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

Во-первых, там все уже есть из коробки установка и запуск потребует минут 30, с учётом всех пререквизитов.

Во-вторых, благодаря мощной команде разработчиков, они не только бирут State Of Art в Hand Pose Estimation, но и дают лёгкое в понимание API.

В-третьих, сеть готова работать на CPU, так что порог входа минимален.

Наверное, вы спросите почему я не зашёл вот сюда и не воспользовался репозиториями победителей этого соревнования. На самом деле я довольно подробно изучил их решение, они вполне prod-ready, никаких стаков миллионов сеток и т.д. Но самая большая проблема, как мне кажется это то, что они работают с изображением глубины. Так как это академики, они не гнушались все данные конвертировать через матлаб, кроме того, разрешение, в котором были отсняты глубины, мне показались маленьким. Это могло сильно сказаться на результате. Поэтому, кажется, что проще всего получить ключевые точки на RGB картинке и по XY координатам взять значение по оси Z в Depth Frame. Сейчас не стоит задача сильно что-то оптимизировать, так что сделаем так, как это быстрее с точки зрения разработки.

Вспоминаем школьную математику



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

На картинке схематично изображена плоскость монитора и линия, ее пересекающая. Посмотреть на математику можно тут

По двум точкам получаем параметрическое представление прямой в пространстве.

image

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

Установка бибилотеки для работы с камерой


Пожалуй, это самая сложная часть этой работы. Как оказалось, софт для камеры под Ubuntu очень сырой, librealsense просто завален все возможными багами, глюками и танцами с бубном.
До сих пор мне не удалось победить странное поведение камеры, иногда она не подгружает параметры при запуске.
Камера работает только один раз после рестарта компьютера!!! Но есть решение: перед каждым запуском делать програмно hard reset камеры, резет usb, и, может быть, всё будет хорошо. Кстати для Windows 10 там все нормально. Странно разработчики себе представляют роботов на базе винды =)

Чтобы под Ubuntu 20 у вас завелся realsense, сделайте так:
$ sudo apt-get install libusb-1.0-0-devThen rerun cmake and make install. Here is a complete recipe that worked for me:$ sudo apt-get install libusb-1.0-0-dev$ git clone https://github.com/IntelRealSense/librealsense.git$ cd librealsense/$ mkdir build && cd build$ cmake ../ -DFORCE_RSUSB_BACKEND=true -DBUILD_PYTHON_BINDINGS=true -DCMAKE_BUILD_TYPE=release -DBUILD_EXAMPLES=true -DBUILD_GRAPHICAL_EXAMPLES=true$ sudo make uninstall && make clean && make && sudo make install


Собрав из сорцов, оно будет более или менее стабильно.
Месяц общения с техподдержкой выявил, что надо ставить Ubuntu 16 или страдать. Я выбрал сами понимаете что.

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



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


Это, как вы поняли, не тряска моих рук, на праздниках я выпил всего одну кружку New England DIPA =) Все дело в постоянных флуктациях ключевых точек и Z-координаты на основе значений, получаемых от лидара.
Посмотим вблизи:


В нашей SOTA от mediapipe флуктаций конечно меньше, но они тоже есть. Как выяснилось, они борются с этим путём прокидывания из прошлого кадра heatmap в текущий кадр и обучают сеть это даёт больше стабильности, но не 100%.

Еще, как мне кажется, играет роль специфика разметки. Врядли можно сделать на таком колличестве кадров одинаковую разметку, не говоря уже о том, что разрешение кадра везде разное и не очень большое. Также мы не видим мерцание света, которое, вероятнеё всего, не постоянно из-за разного периода работы и величины экспозиции камеры. И еще сеть возращает бутерброд из heatmap, равный количеству ключевых точек на экране, размер этого тензора BxNx96x96, где N это кол-во ключевых точек, и, конечно же, после threshold и resize к оригинальному размеру кадра, мы получаем то что получаем =(

Прмер визуализации heatmap:
image

Обзор кода


Весь код находится в этом репозитории и он очень короткий. Давайте разберём основной файл, а остальное вы посмотрите сами.
import cv2import mediapipe as mpimport numpy as npimport pyautoguiimport pyrealsense2.pyrealsense2 as rsfrom google.protobuf.json_format import MessageToDictfrom mediapipe.python.solutions.drawing_utils import _normalized_to_pixel_coordinatesfrom pynput import keyboardfrom utils.common import get_filtered_values, draw_cam_out, get_right_indexfrom utils.hard_reset import hardware_resetfrom utils.set_options import set_short_rangepyautogui.FAILSAFE = Falsemp_drawing = mp.solutions.drawing_utilsmp_hands = mp.solutions.hands# инициализируем mediapipe для Hand Pose Estimationhands = mp_hands.Hands(max_num_hands=2, min_detection_confidence=0.9) def on_press(key):    if key == keyboard.Key.ctrl:        pyautogui.leftClick()    if key == keyboard.Key.alt:        pyautogui.rightClick()def get_color_depth(pipeline, align, colorizer):    frames = pipeline.wait_for_frames(timeout_ms=15000) # ождидаем фрейм от камеры    aligned_frames = align.process(frames)     depth_frame = aligned_frames.get_depth_frame()    color_frame = aligned_frames.get_color_frame()    if not depth_frame or not color_frame:        return None, None, None    depth_image = np.asanyarray(depth_frame.get_data())    depth_color_image = np.asanyarray(colorizer.colorize(depth_frame).get_data())    color_image = np.asanyarray(color_frame.get_data())    depth_color_image = cv2.cvtColor(cv2.flip(cv2.flip(depth_color_image, 1), 0), cv2.COLOR_BGR2RGB)    color_image = cv2.cvtColor(cv2.flip(cv2.flip(color_image, 1), 0), cv2.COLOR_BGR2RGB)    depth_image = np.flipud(np.fliplr(depth_image))    depth_color_image = cv2.resize(depth_color_image, (1280 * 2, 720 * 2))    color_image = cv2.resize(color_image, (1280 * 2, 720 * 2))    depth_image = cv2.resize(depth_image, (1280 * 2, 720 * 2))    return color_image, depth_color_image, depth_imagedef get_right_hand_coords(color_image, depth_color_image):    color_image.flags.writeable = False    results = hands.process(color_image)    color_image.flags.writeable = True    color_image = cv2.cvtColor(color_image, cv2.COLOR_RGB2BGR)    handedness_dict = []    idx_to_coordinates = {}    xy0, xy1 = None, None    if results.multi_hand_landmarks:        for idx, hand_handedness in enumerate(results.multi_handedness):            handedness_dict.append(MessageToDict(hand_handedness))        right_hand_index = get_right_index(handedness_dict)        if right_hand_index != -1:            for i, landmark_list in enumerate(results.multi_hand_landmarks):                if i == right_hand_index:                    image_rows, image_cols, _ = color_image.shape                    for idx, landmark in enumerate(landmark_list.landmark):                        landmark_px = _normalized_to_pixel_coordinates(landmark.x, landmark.y,                                                                       image_cols, image_rows)                        if landmark_px:                            idx_to_coordinates[idx] = landmark_px            for i, landmark_px in enumerate(idx_to_coordinates.values()):                if i == 5:                    xy0 = landmark_px                if i == 7:                    xy1 = landmark_px                    break    return color_image, depth_color_image, xy0, xy1, idx_to_coordinatesdef start():    pipeline = rs.pipeline() # инициализируем librealsense    config = rs.config()     print("Start load conf")    config.enable_stream(rs.stream.depth, 1024, 768, rs.format.z16, 30)    config.enable_stream(rs.stream.color, 1280, 720, rs.format.bgr8, 30)    profile = pipeline.start(config)     depth_sensor = profile.get_device().first_depth_sensor()    set_short_range(depth_sensor) # загружаем параметры для работы на маленьком расстоянии    colorizer = rs.colorizer()    print("Conf loaded")    align_to = rs.stream.color    align = rs.align(align_to) # совокупляем карту глубины и цветную картинку    try:        while True:            color_image, depth_color_image, depth_image = get_color_depth(pipeline, align, colorizer)            if color_image is None and color_image is None and color_image is None:                continue            color_image, depth_color_image, xy0, xy1, idx_to_coordinates = get_right_hand_coords(color_image,                                                                                                 depth_color_image)            if xy0 is not None or xy1 is not None:                z_val_f, z_val_s, m_xy, c_xy, xy0_f, xy1_f, x, y, z = get_filtered_values(depth_image, xy0, xy1)                pyautogui.moveTo(int(x), int(3500 - z))  # 3500 хард код специфичый для моего монитора                if draw_cam_out(color_image, depth_color_image, xy0_f, xy1_f, c_xy, m_xy):                    break    finally:        hands.close()        pipeline.stop()hardware_reset() # делаем ребут камеры и ожидаем её появленияlistener = keyboard.Listener(on_press=on_press) # устанавливаем слушатель нажатия кнопок клавиатурыlistener.start()start() # запуск программы


Я не стал использовать классы или потоки, потому что для такого простого случая достаточно всё выполнять в основном потоке в бесконечном цикле while.

В самом начале происходит инициализация mediapipe, камеры, загрузка настроек камеры для работы short range и вспомогательных переменных. Следом идёт магия под названием alight depth to color эта функция ставит в соответсвие каждой точки из RGB картинки, точку на Depth Frame, то есть даёт нам возможность получать по координатам XY, значение Z.

Понято что необходимо произвести калибровку на вашем мониторе. Я специально не стал вытаскивать отдельно эти параметры, что бы читатель решивший запустить код сделал это сам, за одно резберётся в коде =)

Далее мы берём из всего предсказания только точки под номером 5 и 7 правой руки.
image

Осталось дело за малым полученные координаты фильтруем с помощью скользящего среднего. Можно было конечно применить более серьзные алгоритмы фильтрации, но взглянув на их визуализацию и подёргав разные рычажки, стало понятно, что для демо вполне хватит и скользящего среднего с глубиной 5 фреймов, хочу заметить что для XY вполне хватало и 2-3-х, но вот с Z дела обстоят хуже.
deque_l = 5x0_d = collections.deque(deque_l * [0.], deque_l)y0_d = collections.deque(deque_l * [0.], deque_l)x1_d = collections.deque(deque_l * [0.], deque_l)y1_d = collections.deque(deque_l * [0.], deque_l)z_val_f_d = collections.deque(deque_l * [0.], deque_l)z_val_s_d = collections.deque(deque_l * [0.], deque_l)m_xy_d = collections.deque(deque_l * [0.], deque_l)c_xy_d = collections.deque(deque_l * [0.], deque_l)x_d = collections.deque(deque_l * [0.], deque_l)y_d = collections.deque(deque_l * [0.], deque_l)z_d = collections.deque(deque_l * [0.], deque_l)def get_filtered_values(depth_image, xy0, xy1):    global x0_d, y0_d, x1_d, y1_d, m_xy_d, c_xy_d, z_val_f_d, z_val_s_d, x_d, y_d, z_d    x0_d.append(float(xy0[1]))    x0_f = round(mean(x0_d))    y0_d.append(float(xy0[0]))    y0_f = round(mean(y0_d))    x1_d.append(float(xy1[1]))    x1_f = round(mean(x1_d))    y1_d.append(float(xy1[0]))    y1_f = round(mean(y1_d))    z_val_f = get_area_mean_z_val(depth_image, x0_f, y0_f)    z_val_f_d.append(float(z_val_f))    z_val_f = mean(z_val_f_d)    z_val_s = get_area_mean_z_val(depth_image, x1_f, y1_f)    z_val_s_d.append(float(z_val_s))    z_val_s = mean(z_val_s_d)    points = [(y0_f, x0_f), (y1_f, x1_f)]    x_coords, y_coords = zip(*points)    A = np.vstack([x_coords, np.ones(len(x_coords))]).T    m, c = lstsq(A, y_coords)[0]    m_xy_d.append(float(m))    m_xy = mean(m_xy_d)    c_xy_d.append(float(c))    c_xy = mean(c_xy_d)    a0, a1, a2, a3 = equation_plane()    x, y, z = line_plane_intersection(y0_f, x0_f, z_val_s, y1_f, x1_f, z_val_f, a0, a1, a2, a3)    x_d.append(float(x))    x = round(mean(x_d))    y_d.append(float(y))    y = round(mean(y_d))    z_d.append(float(z))    z = round(mean(z_d))    return z_val_f, z_val_s, m_xy, c_xy, (y0_f, x0_f), (y1_f, x1_f), x, y, z


Создаем deque c длинной 5 фреймов и усредняем все подряд =) Дополнительно расчитываем y = mx+c, Ax+By+Cz+d=0, уравнение для прямой луч на RGB картинке и уравнение плоскости монитора, оно у нас получается y=0.

Итоги



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

Благодарности



Спасибо сообществу ods.ai, без него невозможно развиваться!
Подробнее..

Учиться, учиться, и ещё раз учиться?

01.06.2021 14:09:01 | Автор: admin

TLDR: крохотные модельки обошли модные графовые нейронки в предсказании свойств молекул.
Код: здесь. Берегите Природу.


image
ФОТО: Андерс Хеллберг для Wikimedia Commons, модель Грета Тунберг


Необученная графовая свёрточная нейронная сеть [1] (uGCN) со случайной инициализацией весов уже пару лет занимает первое место в моём списке алгоритмов для задач машинного обучения на графах из-за копеечной стоимости, простоты реализации, да вполне очевидной элегантности решения. В то же время, насколько мне известно, никто ещё не не проводил соревнований между этой простой моделью и её старшей сестрой полноценно обученной графовой свёрточной нейронной сетью (GCN) в режиме обучения с учителем. Вот я сделал.


Мотивация: показать, что uGCN выдаёт качественные представления, которые можно использовать в последующих задачах машинного обучения в индуктивном режиме, когда модели обобщаются к не виденным ранее данным (вдохновлено недавним отчётом [2] о производительности простых моделей в трансдуктивном случае).


Полученные результаты занимательны. В худшем случае простые модели (uGCN + degree kernel + random forest) показали счёт 54:90 против полноценно обученных GCN, в то время как реалистичный сценарий закончился разгромным реваншем 93:51, указывающим на то, что мы можем позволить себе почти бесплатные эмбеддинги, которые превосходят или показывают результаты на уровне полноценно обученных GCN в задаче предсказания свойств графа (например эффекта медикаментов: яд или лекарство) за долю стоимости. Простые модели обучались ~10 минут в то время как весь эксперимент продлился ~4 часа. Перейдём же к деталям и разберёмся с тем, что произошло!


Основные понятия


Многие из важных наборов данных об окружающем нас мире имеют связный характер: социальные сети, графы знаний, взаимодействия белков, всемирная паутина WWW и т.д. (просто несколько примеров) [1].


Граф, обыкновенно записываемый как G=(V, E) это математическая модель, множество множеств, состоящее из набора вершин V и множества рёбер E попарных связей e(i, j) между вершинами i и j. Расширением Графа является модель Граф со Свойствами (Labeled Property Graph), позволяющий задать вектор признаков xi для вершины i (мы также можем определять свойства для рёбер, однако это выходит за рамки сегодняшнего эксперимента). Графовая нейронная сеть [3] (GNN) это модель машинного обучения (параметрическая функция, которая подбирает, другими словами выучивает, параметры из данных), расширяющая возможности хорошо известного семейства алгоритмов, вдохновлённых биологией, до работы с неструктурированными данными в виде графов. На мой взгляд, передача сообщений это самая простая интуиция для понимания механики работы GNN и вполне оправдано обратиться к мнемоническому правилу 'скажи мне, кто твой друг и я скажу тебе кто ты'. Графовые свёрточные нейронные сети (GCN) очень подробно описал их изобретатель здесь (https://tkipf.github.io/graph-convolutional-networks/) и мне, право, непросто что-то ещё добавить к этой замечательной истории.


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


image


Многослойная GCN с фильтрами первого порядка.


Данные


Проведём серию экспериментов на общедоступных данных. Мы обратимся к (i) коллекции TUDatasets [4] и (ii) ограничим наше упражнение задачей бинарной классификации (предсказанием свойств) небольших молекул. Ещё одним условием нашего мероприятия будет (iii) использование графов с признаками вершин.


Заданные ограничения оставляют нам несколько наборов данных, широко используемых для сравнения современных алгоритмов. Вот наш итоговый список: AIDS, BZR, COX2, DHFR, MUTAG и PROTEINS. Все обозначенные наборы данных доступны как часть Pytorch Geometric [5] (библиотека для глубокого обучения на графах) в двух версиях: оригинальной и очищенной от дубликатов [6]. Итого у нас будет 12 датасетов.


AIDS Antiviral Screen Data [7]


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


Benzodiazepine receptor (BZR) ligands [8]


Оригинальный набор содержит 405 молекул, очищенная версия 276, по 35 признаков на вершину.


Cyclooxygenase-2 (COX-2) inhibitors [8]


Оригинальный набор содержит 467 молекул, очищенная версия 237, по 35 признаков на вершину.


Dihydrofolate reductase (DHFR) inhibitors [8]


Оригинальный набор содержит 756 молекул, очищенная версия 578, 35 признаков на вершину.


MUTAG [9]


В наборе содержится 188 химических соединений, разделённых на два класса согласно их мутагенному воздействию на бактерии. В очищенной версии 135 молекул, 7 признаков на вершину.


PROTEINS [10]


Энзимы и не-энзимы. В оригинальном наборе содержится 1113 молекул, по 3 признака на вершину. Очищенная версия 975 структур.


Дизайн Эксперимента


Мы устроим турнир!


Для каждого набора данных проведём 12 раундов обучения и тестирования.


В каждом раунде:


(1) псевдослучайным образом разделим данные в пропорции 80/20 в Pytorch Geometric (начиная со стартового параметра генератора random seed = 42 и увеличивая его на единицу в каждом последующем раунде), таким образом 80% точек данных (графов) будут использованы в качестве обучающей выборки, а оставшиеся 20% будут тестовой выборкой;


(2) обучим модели и оценим долю верных ответов (accuracy) на тесте.


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


Для GCN мы проводим 200 эпох обучения и тестирования со скоростью обучения learning rate = 0.01 и принимаем во внимание:
(А) среднее значение доли верных ответов для 10 финальных эпох обучения реалистичный сценарий;
(В) наибольшее значение доли верных ответов, достигнутое в процессе обучения (как если бы мы сохраняли промежуточное состояние для того, чтобы выбрать наилучшую модель впоследствии) наилучший сценарий для GCN (и наихудший для простых моделей);


(3) лучшей модели присуждается 1 балл;


(4) в случае ничьей балл присуждается лёгкой модели.


Всего будет распределено 288 баллов: 12 датасетов 12 раундов 2 сценария.


Модели


Degree kernel (DK) или степенное ядро гистограмма степеней вершин (количество рёбер, соединённых с вершиной), нормированная к числу вершин в графе (таким образом вектор признаков для каждого графа состоит из размеров долей вершин с количеством связей, равным индексу признака, от всего множества вершин в сумме они дают единицу).


import networkx as nximport numpy as np from scipy.sparse import csgraph# g - граф формате популярной библиотеки NetworkXnumNodes = len(g.nodes)degreeHist = nx.degree_histogram(g)# нормализуемdegreeHist = [x/numNodes for x in degreeHist]

Необученная графовая свёрточная нейронная сеть (uGCN) со случайной инициализацией весов 3 слоя с промежуточной нелинейной активацией (ReLU, т.е. f(x) = max(x, 0)). Аггрегация усреднением полученных после прямого прохода 64-разрядных векторов (эмбеддинги вершин) позволяет получить компактное представление графа. Это на самом деле очень просто.


A = nx.convert_matrix.to_scipy_sparse_matrix(g)

Воспользуемся вариантом реализации одного слоя свёртки в три строки, который пару лет назад предложил iggisv9t :


# A - матрица связности графа# X - матрица признаков вершин (np.array)D = sparse.csgraph.laplacian(A, normed=True)shape1 = X.shape[1]X = np.hstack((X, (D @ X[:, -shape1:])))

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


Разберём его на части и пересоберём заново.


Использованная реализация uGCN выглядит так:


# A - матрица связности графа# X - матрица признаков вершин (np.array)# W0, W1, W2 - случайным образом инициализированные весаD = sparse.csgraph.laplacian(A, normed=True)# слой 0Xc = D @ X @ W0# ReLUXc = Xc * (Xc>0)# конкатенация признаков вершин с аггрегированной информацией соседейXn = np.hstack((X, Xc))# слой 1Xc = D @ Xn @ W1# ReLUXc = Xc * (Xc>0)Xn = np.hstack((Xn, Xc))# слой 2 - эмбеддинги вершинXc = D @ Xn @ W2# аггрегация усреднением - эмбеддинг графаembedding = Xc.sum(axis=0) / Xc.shape[0]

Комбинация DK и uGCN (Mix) конкатенацией представлений графа, полученных с помощью моделей DK и uGCN.


mix = degreeHist + list(embedding)

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


Графовая свёрточная нейронная сеть (GCN) полноценно обученный классификатор, состоящий из 3 свёрточных слоёв размерностью 64 с промежуточной нелинейной активацией (ReLU), агрегацией усреднением (до этого момента архитектура GCN очень похожа на uGCN), за которой следует слой регуляризации дропаутом (произвольным обнулением разрядов с вероятностью 50%) и линейный классификатор. Мы будем обозначать результаты модели, отобранные в наилучшем для GCN сценарии (B) как GCN-B, а модели в реалистичном сценарии (А) как GCN-A.


Результаты


После 144 раундов (12 датасетов * 12 раундов) сравнения качества предсказаний на отложенной выборке между простыми моделями и полноценно обученными графовыми свёрточными сетями 288 баллов распределились как:


147:141


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


image


Наборы данных, в которых простые модели побеждают: AIDS, DHFR(A) и MUTAG.


Например, DK собрала все 48 баллов для набора данных AIDS, демонстрируя отрыв более чем на 10% (абсолютное значение) от доли верных ответов полноценно обученной GCN.


image


Здесь побеждают GCN: BZR, COX2 и PROTEINS.


Индивидуальный зачёт:
90 GCN-B;
71 DK;
55 Mix (uGCN + DK);
51 GCN-A;
21 uGCN.


Достаточно подробный протокол соревнований приведён в блокнотике с кодом, таблица с результатами раундов здесь.


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


Выводы


Как видим, проведенный эксперимент подтверждает предположение о том, что в задаче предсказания свойств молекул мы можем позволить себе использовать почти бесплатные эмбеддинги, которые превосходят или показывают результаты на уровне полноценно обученных нейронных сетей. Наблюдения согласуются с вдохновляющими этот эксперимент результатами [2] в том, что концептуально метод Label Propagation очень похож на передачу сообщений в графовой свёрточной нейронной сети. Объяснение эффективности скорее всего следует искать в том, что на самом деле мощнее подбирать параметры фильтров для того, чтобы внутренние представления, выученные сетью стали линейно разделимыми, либо же просто использовать классификатор помощнее, как это сделано в рассмотренном примере.


Дисперсия результатов между раундами соревнования напоминает о том, что всякое сравнение дело непростое. Здесь стоит упомянуть Free Lunch Theorem и напомнить о том, что использовать сразу несколько моделей в построении решения скорее хороший тон. Также важно отметить влияние разбиения на выборки в ходе сравнения на одном и том же наборе данных одна и та же модель может показывать очень разное качество. Поэтому сравнивая модели, убедитесь, что обучаете и тестируете их на идентичных выборках. К слову, фиксация параметров генератора псевдослучайных чисел не панацея


image


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


Послесловие


В лекции открытого курса по графам знаний GCN названа Королевской Лазейкой Через Пространство Фурье, этот ярлык приклеился с тех пор, когда впервые выступил на публике с рассказом о силе графов и провёл первые эксперименты с классификацией картинок (как графов) для того, чтобы продемонстрировать мощь спектральных фильтров одной юной леди, запускавшей стартап в милой моему сердцу аэрокосмической области. Данная заметка появилась в результате того, что пару недель назад в реальной задаче на закрытых данных uGCN, вместе с простенькими моделями показали результат, который полноценно обученные GCN смогли превзойти всего на 2% (96 против 98) и мне вздумалось проверить вопрос о том, кто кого заборет ещё на каких-нибудь данных.


В наши дни машинное обучение на графах превратилось в знаменитость, всё больше исследователей обращают внимание на эту область и новые архитектуры графовых нейронных сетей появляются каждую неделю. Однако на самом деле мы ещё не очень хорошо понимаем почему GNN так успешны и нужны ли они для хорошего качества решения [2].


Перед тем, как ступать на очаровательный путь машинного обучения на графах, пожалуйста ознакомьтесь с основами этого дела. Значительные усилия прилагаются к тому, чтобы сделать новейшие достижения (да и классические методы тоже) доступными широкой аудитории совершенно бесплатно. Упомяну лишь несколько из таких инициатив: материалы и лекции стенфордского cs224w, площадку для тестирования качества алгоритмов Open Graph Benchmark [14] и недавнюю работу об основах геометрического глубокого обучения [15] методологию разработки новых архитектур нейронных сетей. Напоследок, ещё раз напомню о том, что начинать проекты машинного обучения стоит с простых методов, вроде ядер и необученных графовых свёрточных сетей достаточно часто эти модельки показывают неприлично хороший уровень.


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


image


Литература


[1] Kipf & Welling, Semi-Supervised Classification with Graph Convolutional Networks (2017), International Conference on Learning Representations;
[2] Huang et al., Combining Label Propagation and Simple Models out-performs Graph Neural Networks (2021), International Conference on Learning Representations;
[3] Scarselli et al., The Graph Neural Network Model (2009), IEEE Transactions on Neural Networks ( Volume: 20, Issue: 1, Jan. 2009);
[4] Morris et al.,TUDataset: A collection of benchmark datasets for learning with graphs (2020), ICML 2020 Workshop on Graph Representation Learning and Beyond;
[5] Fey & Lenssen, Fast Graph Representation Learning with PyTorch Geometric (2019), ICLR Workshop on Representation Learning on Graphs and Manifolds;
[6] Ivanov, Sviridov & Burnaev, Understanding isomorphism bias in graph data sets (2019), arXiv preprint arXiv:1910.12091;
[7] Riesen & Bunke, IAM Graph Database Repository for Graph Based Pattern Recognition and Machine Learning (2008), In: da Vitora Lobo, N. et al. (Eds.), SSPR&SPR 2008, LNCS, vol. 5342, pp. 287-297;
[8] Sutherland et al., Spline-fitting with a genetic algorithm: a method for developing classification structure-activity relationships (2003), J. Chem. Inf. Comput. Sci., 43, 1906-1915;
[9] Debnath et al., Structure-activity relationship of mutagenic aromatic and heteroaromatic nitro compounds (1991), J. Med. Chem. 34(2):786-797;
[10] Dobson & Doig, Distinguishing enzyme structures from non-enzymes without alignments (2003), J. Mol. Biol., 330(4):771783;
[11] Pedregosa et al., Scikit-learn: Machine Learning in Python (2011), JMLR 12, pp. 2825-2830;
[12] Waskom, seaborn: statistical data visualization (2021), Journal of Open Source Software, 6(60), 3021;
[13] Hunter, Matplotlib: A 2D Graphics Environment (2007), Computing in Science & Engineering, vol. 9, no. 3, pp. 90-95;
[14] Hu et al., Open Graph Benchmark: Datasets for Machine Learning on Graphs (2020), arXiv preprint arXiv:2005.00687;
[15] Bronstein et al., Geometric Deep Learning: Grids, Groups, Graphs, Geodesics, and Gauges (2021), arXiv preprint arXiv:2104.13478.

Подробнее..

Рубрика Читаем статьи за вас. Май 2020. Часть 1

15.06.2020 14:21:28 | Автор: admin


Привет, Хабр! Продолжаем публиковать рецензии на научные статьи от членов сообщества Open Data Science из канала #article_essense. Хотите получать их раньше всех вступайте в сообщество!


Статьи на сегодня:


  1. Efficient Document Re-Ranking for Transformers by Precomputing Term Representations; EARL: Speedup Transformer-based Rankers with Pre-computed Representation (2020)
  2. MakeItTalk: Speaker-Aware Talking Head Animation (Adobe, University of Massachusetts Amherst, Huya, 2020)
  3. Jukebox: A Generative Model for Music (OpenAI, 2020)
  4. Recipes for building an open-domain chatbot (Facebook AI Research, 2020)
  5. One-Shot Object Detection without Fine-Tuning (HKUST, Hong Kong, Tencent, 2020)
  6. f-BRS: Rethinking Backpropagating Refinement for Interactive Segmentation (Samsung AI Center, Moscow, 2020)
  7. Flowtron: an Autoregressive Flow-based Generative Network for Text-to-Speech Synthesis (NVIDIA, 2020)


1. Efficient Document Re-Ranking for Transformers by Precomputing Term Representations; EARL: Speedup Transformer-based Rankers with Pre-computed Representation


Авторы статьи 1: Sean MacAvaney, Franco Maria Nardini, Raffaele Perego, Nicola Tonellotto, Nazli Goharian, Ophir Frieder (USA, Italy, 2020)
Авторы статьи 2: Luyu Gao, Zhuyun Dai, Jamie Callan (Carnegie Mellon University, USA, 2020)
Оригинал статьи 1 :: Оригинал статьи 2
Автор обзора: Владимир Бугай (в слэке smartvlad, на habr vbougay)


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


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


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


В классическом варианте для каждой пары запрос-документ формируется вход трансформера и прогоняется через все слои. Тем самым для одного и того же запроса его векторное представление рассчитывается сотни раз, а в случае множества запросов то же самое происходит для документов. Авторы предлагают немного затюнить классический трансформер и выделить в нем явно модули рассчитывающие представление запроса и документа, так, чтобы вместо их расчета каждый раз, результат можно было закешировать и использовать для повторных расчетов избегая массы ненужных вычислений. Такой подход позволил добиться ускорения реранжирования в 40 раз без заметной потери в качестве. В первой статье результаты оценивали на WebTrack 2012, во второй на MS Marco. Результаты сравнивали с Vanilla BERT.


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



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




Архитектура модели EARL, тут явно выделили блоки запроса и документа (почти сиамская сетка), а дальше сводят их в блок-оценщик (Judger).



Качество модели PreTRR с кэшированием разного количества слоев, а также ее производительность при реранжировании 100 документов.





2. MakeItTalk: Speaker-Aware Talking Head Animation


Авторы статьи: Yang Zhou, DIngzeyu Li, Xintong Han, Evangelos Kalogerakis, Eli Shechtman, Jose Echevarria (Adobe, University of Massachusetts Amherst, Huya, 2020)
Оригинал статьи
Автор обзора: Евгений Кашин (в слэке digitman, на habr digitman)


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




Из исходного лица достают 68 кейпоинтов. Входной звук процесят (мел спектрограмма) и пропускают через два разных претрейн энкодера (conv-ы c lstm). Content embedding достает информацию о словах (фонемах), не цепляясь за "идентичность". Контент эмбединг (окнами по 300мс) идет в LSTM, а после конкатится с кейпоинтами и пропускается через MLP, для предсказания смещения начальных кейпоинтов. На этом шаге должно предсказываться новое положение лица (кейпоинтов) для текущего звука, но с нейтральным выражением лица. Важно предсказывать смещения координат, а не абсолютные, чтобы нормально работало на мультяшных лицах.


Speaker Identity embedding извлекает личность из голоса. Использовали модель аудио верификации, которая обучалась выдавать близкие эмбединги для одного человека. В этом блоке (нижний на схеме) опять использовали контент эмбединг + LSTM (другие веса), выход которого конкатили со спикер эмбедингом и подавали в self attention (с временным окном 4 секунды, чтобы лучше учесть мотания головой). В конце выдаются также предсказания смещения кейпоинтов.




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




Для реальных лиц использовали image2image сетку(U-net like). На входе конкатенация исходного изображения и таргет ландмарок, полученных на предыдущем шаге. Ландмарки соединяют в группы и заливают разными цветами.


Для обучения контент ветки использовали датасет 6 часов видео с Обамой, кейпоинты выровнены, поэтому не было движения головы, а только мимика лица(как не странно, одного человека было достаточно). Лосс l2 между кейпоинтами и l2 между локально сгруппированными кейпоинтами (respective graph Laplacian coordinates).


Для speaker aware ветки нужен был датасет с большим разнообразием людей VoxCeleb2. Тут наоборот не выравнивали ландмарки, чтобы оставить мотания головой. Использовали ган лосс, для того чтобы мотания и эмоциональность частей лица выглядели реалистично. Дискриминатор тоже с self attention, лосс LSGAN. К адвесериал лоссу на кейпоинты также были лоссы из контент ветки.


Для обучения image2image тоже VoxCeleb2, для одного человека семплили случайную сорс картинку и таргет (превращенный в изображение из ландмарок). Лосс l1 и perceptual vgg loss.


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




3. Jukebox: A Generative Model for Music


Авторы статьи: Prafulla Dhariwal, Heewoo Jun, Christine Payne, Jong Wook Kim, Alec Radford, Ilya Sutskever (OpenAI, 2020)
Оригинал статьи :: GitHub project :: Blog
Автор обзора: Александр Бельских (в слэке belskikh)


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


Пайплайн использует hierarchical Vector Quantized VAE (VQ-VAE), чтобы сжать аудио в дискретное пространство с лосс-функцией построенной так, чтоб сохранить максимум музыкальной информации. Поверх этого сжатого пространства используются авторегресионные Sparse Transformers, а также авторегресионные апсемплеры, чтобы расжать представления. Используется три отдельных VQ-VAE для трёх разных уровней сжатия и детализации.


Суть VQ-VAE в том, что он квантизует эмбеддинги в ботлнеке, используя Codebook это обучаемый набор эмбеддингов. На выходе из энкодера полученных эмбеддинг сравнивается со всеми в Codebook, а в декодер затем подаётся ближайший эмбеддинг из Codebook. Такой способ уменьшения разнообразия помогает декодеру.




После обучения VQ-VAE необходимо научиться генерировать сэмплы из сжатого пространства, причем со всех трёх уровней последовательно. Для этого обучаются Transformers with sparse attention, так как они сота для авторегрессии. Для апсемплинга трансофрмерам необходимо дать conditonal информацию из кодов верхнего уровня. Для этого используют deep residual WaveNet по небольшому окну кодов верхнего уровня, их аутпут добавляют в апсемплеры.


Чтобы задать условия на артиста и жанр, для песен докидывались соответствующие лейблы. Этого не хватало, чтоб генерить внятную и различимую речь, поэтому стали дополнительно задавать условие ещё и текстом. Задать текст как условие в песню задача нетривиальная, так как нужно выровнять относительно времени текст + получить чистую разметку.


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


После того, как обучен VQ-VAE, апсемплеры и приоры топ-уровней, их можно использовать для сэмплирования. Сначала генерируется топ-левел коды по одному токену за раз: сначала генерируется первый токен, затем все предыдущие токены подаются в модель как инпуты, чтобы выдать аутпут токен, conditioned на всех предыдущих.




VQ-VAE обучался 3 дня на 256хV100. Апсемплеры обучались 2 недели на 128xV100. Приоры обучались 4 недели на 512xV100.


В результате получилась первая в своём роде модель, которая может генерить правдоподобно звучащие целые песни, комбинировать стили, продолжать композиции и т. п. У текущей модели генерация одной минуты топ-левел токенов занимает примерно час. И примерно 8 часов нужно, чтоб сделать апсемпл одной минуты топ-левел токенов.


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


4. Recipes for building an open-domain chatbot


Авторы статьи: Stephen Roller, Emily Dinan, Naman Goyal, Da Ju, Mary Williamson, Yinhan Liu, Jing Xu, Myle Ott, Kurt Shuster, Eric M. Smith, Y-Lan Boureau, Jason Weston (Facebook AI Research, 2020)
Оригинал статьи :: Open source :: Blog :: Colab
Автор обзора: Артем Родичев (в слэке fuckai)


Фейсбук натренировал и зарелизил SOTA open-domain чатбот модель. Лучшая модель имеет 2.7В параметров, самая большая 9.4B. По архитектуре трансформер. На human evaluation модель от FB получилась сильно лучше прошлой SOTA модели Meena от гугла.


Выложили все код, модель и датасеты для файнтюна. В дополнении к Meena показали по сути два способа увеличения качества ответов модели:


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

Суть
Натренировали и сравнили друг с другом разные типы диалоговых моделей:


  • retrieval-based На вход контекст и датасет респонсов, на выходе нужно выдать топ релевантных респонсов из датасета. Использовали Poly-encoder модель, по сути усовершенствованный двубашенный трансформер-енкодер, где одна башня енкодер контекста, вторая енкодер респонса, на выходе dot product, показывающий релевантность респонса для данного контекста.
  • генеративные На входе контекст, на выходе нужно сгенерировать респонс. Архитектура encoder-decoder transformer, малослойный енкодер, многослойный декодер. Натренировали три базовые модели отличающиеся количеством параметров: 90M, 2.7B (ровно как в Meena), 9.4B.
  • retrieve and refine Смесь двух подходов выше. Сначала получаем список кандидатов из retrieval-based модели, и подаем их в качестве подсказок в генеративную модель для генерации финального ответа.

Все базовые модели тренировали на огромной корпусе реддита. Финальный очищенный корпус имеет 1.5B диалоговых сообщений. Сколько учились и на каком железе не написали.


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


  • добавление unlikelihood лосса. По сути в лосс добавляем штраф за порождение частотных нграмм, чтобы форсить разнообразие слов и коллокаций при генерации ответа.
  • subsequence blocking. Выбрасываем респонсы у которых есть нграмное пересечение с контекстом, или же одна нграмма несколько раз встречается в самом ответе, т.e модель повторяет, то что уже сказала.
  • файнтюн. Рассмотрели 4 небольших диалоговых корпуса, от 50K до 200K сообщений в каждом: ConvAI2, Empathetic Dialogs, Wizard of Wikipedia и BST(Blended Skill Talk) по сути объединение трех первых корпусов. Лучше всего файнтюн заработал на BST.
  • декодинг алгоритмы. Пробовали beamsearch с разными beamsize, top-k сэмплирование, sample + rank как в Meena когда вначале сэмплим N ответов, а потом выбираем лучший по log-likelihood. В итоге лучшим оказался beamsearch (beam=10) c ограничением на длину, в котором они форсят генерировать ответ минимум в 20 токенов. Показали что таким образом увеличивается как качество ответов, так и engagingness вовлеченность человека в беседу с чатботом.

Результаты
Для финального сравнения моделей использовали способ ACUTE-Eval. Состоит из двух шагов: шаг 1 с помощью асессоров набираем N диалогов между людьми и нашими разными моделями, шаг 2 даем новым людям-асессором сделать side-by-side сравнение даем прочитать два диалога с разными чатботами и просим ответить какого чатбота асессор бы предпочел для дальнейшего общения. Такой подход позволяет сравнивать модели просто имея сэмплы диалогов и не имея доступ к самой модели. Именно так и получилось с Meena, где выложили примеры диалогов, но не выложили саму модель.


По итогу самая лучшая модель BST Generative на 2.7B с бимсерчем = 10 и ограничением минимальной длины ответа в 20 токенов. Удивительно, что 9.4B модель проиграла 2.7B модели на side-by-side сравнении по engagingness 54% проголосовали за 2.7B модель, хотя по perplexity 9.4B получилась лучше.




Еще удивительно, что на side-by-side сравнении диалогов их лучшей модели и диалогов человек-человек, по метрике engagingness они сматчились с человеческими. Недалек тот день, когда можно будет выбросить всех друзей и увлекательно общаться только с чатботами.



В заключении провели анализ ошибок модели, типичные факапы:


  • противоречие и забывчивость. Модель в диалоге может противоречить сама себе или повторяться про те вещи, про которые говорила несколько шагов назад;
  • выдумывание фактов. Модель может придумать и сгенерировать несуществующие факты о реальном мире, отсутствует понимание причинно-следственных связей;
  • чрезмерное использование частотных коллокаций. Намного чаще, чем люди, употребляет безопасные и частотные фразы как do you like, lot of fun, have any hobbies, и другие.

5. One-Shot Object Detection without Fine-Tuning


Авторы статьи: Xiang Li, Lin Zhang, Yau Pun Chen, Yu-Wing Tai, Chi-Keung Tang (HKUST, Hong Kong, Tencent, 2020)
Оригинал статьи
Автор обзора: Александр Бельских (в слэке belskikh)


Микс сиамских сетей с anchor-free детектором FCOS, который позволяет делать детекцию объектов class-agnostic, то есть сетка получает на вход изображение с объектами + отдельный кроп с изображением нужного класса, на выходе выдаёт боксы найденных похожих объектов.




Пайплайн состоит из двух частей: Matching FCOS и Structure-Aware Relation Module.


Модифицированный в сиамскую сеть FCOS детектор, который назвали Matching FCOS.
Он пропускает через один бэкбоун (FPN энкодер-декодер) два изображения query картинку, на которой мы ищем изображение, и support картинку, это кропнутый объект интереса.


Фичи support картинки потом превращаются в вектор с помощью global average pooling и ими делают dot product с фичами картинки query, получая similarity map. По этой мапе делают ещё несколько сверток в параллель, чтоб получить proposals объектов с помощью обычной FCOS головы (где на каждый пиксель фичемапа предиктится class score и координаты бокса).




Structure-Aware Relation Module.
В этом модуле также используются фичи query и support картинок, но из query картинки фичи пулятся с помощью RoI Align по тем proposals, что были сгенерированы на этапе 1. Далее они конкатятся и по ним проезжают несколько pixel-wise сверточных слоёв, после чего снова разветвление на два бранча и предикт класса и уточнение координат бокса. Класс 1 в данном случае означает матч объекта с support, а 0 не матч, то есть background.




По результатам сопоставимы с сотой в One Shot detection, но эту сетку не надо файнтюнить вообще, она архитектурно работает на поиск объектов по запрошенной картинке.




6. f-BRS: Rethinking Backpropagating Refinement for Interactive Segmentation


Авторы статьи: Konstantin Sofiiuk, Ilia Petrov, Olga Barinova, Anton Konushin (Samsung AI Center, Moscow, 2020)
Оригинал статьи :: GitHub project :: Video
Автор обзора: Илья Петров (в слэке ptrvilya)


tl;dr Хотим сделать сегментацию, управляемую юзером, то есть юзер может кликать по картинке, показывая какие области нужно включить в сегментацию, а какие проигнорировать. Как сделать? До нас предлагали после каждого клика просто запускать оптимизацию входа сети, минимизируя ошибку сегментации в указанных пользователем точках. Это точно, но много накладных расходов. Мы предлагаем оптимизировать только небольшой набор параметров внутри сети, а именно scale и bias для фичей фиксированного слоя (специально для этого добавили их как новые параметры) Так мы сохраним точность, сильно подняв скорость. Результат на гифке:




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


Проблема.
Даже хитрая симуляция кликов во время обучения не может заставить предсказанную маску полностью соответствовать им. Год назад предложили следующую идею: после каждого клика минимизировали L2 между предсказанной маской и картой кликов пользователя (1 в позитивных, 0 в негативных, в остальных игнор), а целевой переменной для оптимизации сделали карты расстояний, подаваемые на вход сети. Своего рода adversarial атака с выгодой для результата. Сильная сторона такого подхода в теории, если подать много кликов, то результат за счет оптимизации сойдется в целевой маске, раньше такого гарантировать было нельзя. С другой стороны делать backward несколько раз после каждого клика очень накладно.


Предложенный подход.
Чтобы сохранить преимущества оптимизации, но при этом ускорить, заменили целевые переменные. Оптимизировать промежуточные фичи схожим образом не вариант, так как чем ближе к выходу, тем локальнее будут изменения, при этом вычислительно будет все еще затратно. Вместо этого решили использовать поканальные scale и bias для промежуточных фичей, так как позволяют глобально влиять на промежуточные признаки и результат, но при этом достаточно компактные и находятся близко к выходу. Использовали DeepLabV3+ и три варианта применения scale и bias.




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


Эксперименты.
Стандартная метрика число кликов необходимых для достижения заданного порога по IoU, при этом каждый следующий клик ставится в центр замкнутой области с FP или FN наибольшей площади, а общее число кликов ограничено 20.
Для подтверждения того, что без дополнительной оптимизации сходимость к желаемой маске плохая (это справедливо, как минимум для стандартного датасета, используемого во всех статьях semantic boundaries, качество ) в отдельном эксперименте повысили ограничение до 100 кликов и получили, что после 100 кликов без оптимизации до IoU 90 не сходится в 5 раз больше картинок.




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


7. Flowtron: an Autoregressive Flow-based Generative Network for Text-to-Speech Synthesis


Авторы статьи: Rafael Valle, Kevin Shih, Ryan Prenger, Bryan Catanzaro (NVIDIA, 2020)
Оригинал статьи :: GitHub project :: Blog
Автор обзора: Александр Бельских (в слэке belskikh)


Пионерская работа от NVIDIA по использованию Flow-based модели для генерации text2speech. Основана на Tacotron2, но обладает большей вариативностью + по дефолту даёт возможность оперировать латентным пространством, давая доступ к интонациям и тембру голоса, к той информации, которая отсутствует в обычном тексте. Эта модель озвучивала ролик.


Авторы предлагают новый способ синтеза мел-спектрограмм авторегрессионная flow-based генеративная сеть. Она выучивает обратимую функцию, которая мапит распределение по мел-спектрограмме в сферическое гауссово латентное пространство. Обучается модель, просто максимизируя правдоподобие данных.


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


Благодаря этому можно выполнять style transfer между семплами, менять спикера или просто делать вариации внутри одного спикера, варьируя стандартное отклонение гауссового распределения.


Модель принимает на вход последовательность кадров мел-спектрограмм, выдавая следующую спектрограмму основываясь только на предыдущей спектрограмме. Эти сэмплы проходят через серию обратимых параметризированных аффинных трансформаций, которые мапят z распределение в x (спектрограмму). Это и есть flow.




Во время форвард прохода, собираются мел-спектрограммы как вектора и прогоняются через несколько шагов flow, закондишенных на текст и айди спикера. Шагом flow является affine coupling layer, который является типичным для построения обратимых нейронных сетей. Во время инференса процесс происходит наоборот берётся случайный вектор из Z и прогоняется через модель в обратном режиме.


Модель училась на DGX-1 8хV100.


По Mean Opinion Score модель на одном уровне с Tacotron 2, но обходит его по вариативности и возможностям манипулирования сэмплированием. Сэмплы лучше всего послушать на сайте.



Ссылка на начало

Подробнее..

Рубрика Читаем статьи за вас. Май 2020. Часть 2

25.06.2020 14:15:14 | Автор: admin


Привет, Хабр! Продолжаем публиковать рецензии на научные статьи от членов сообщества Open Data Science из канала #article_essense. Хотите получать их раньше всех вступайте в сообщество!


Статьи на сегодня:


  1. ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks (China, 2020)
  2. TAPAS: Weakly Supervised Table Parsing via Pre-training (Google, 2020)
  3. DeepFaceLab: A simple, flexible and extensible faceswapping framework (2020)
  4. End-to-End Object Detection with Transformers (Facebook AI, 2020)
  5. Language Models are Few-Shot Learners (OpenAI, 2020)
  6. TabNet: Attentive Interpretable Tabular Learning (Google Cloud AI, 2020)


1. ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks


Авторы статьи: Qilong Wang, Banggu Wu, Pengfei Zhu, Peihua Li, Wangmeng Zuo, Qinghua Hu (China, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Эмиль Закиров (в слэке bonlime)


Очередной вариант self-attention для computer vision. Авторы внимательно посмотрели на известный squeeze-and-excitation (SE), который сейчас используют во многих SOTA сеточках и его аналоги, попробов понять почему же именно оно работает. Потом предложили свой супер легкий attention block, который практически не увеличивает количество параметров, быстрее чем SE и при этом лучше работает.




Все последние attention блоки обладают одним из двух свойств, они либо используют уменьшение количества каналов, либо включают какое-то взаимодействие между каналами. SE, к примеру, делает и то и то.




Хочется понять насколько эти две составляющие влияют на итоговое качество. Для этого авторы предлагают несколько слегка модифицированных вариантов SE block:


  • SE-Var1 просто делаем GlobalAvgPool + sigmoid. Даже такой просто attention даёт прирост к качеству.
  • SE-Var2 GlobalAvgPool + каждый канал умножается на какой-то параметр + sigmoid. В отличие от дефолтного SE нет DR и нет cross-channel interaction, а качество выше! Вывод авторов избегание DR важнее чем какие-то cross-channel interactions.
  • SE-Var3 как SE, но без уменьшения количества каналов в середине. Работает лучше, но добавляет очень много параметров и сильно замедляет обучение.
  • SE-GC попытки делать attention через групповые свертки. Работает лучше чем SE, но group convs медленно обучаются.
  • ECA вариант авторов. GlobalAvgPool + Conv1d (kernel size=3). Операция Conv1d дешевая, при этом удалось избежать dimensionality reduction и добавить какое-то cross-channel interaction.



Attention block авторов в деталях.
Размер ядра после GlobalAvgPool можно пытаться определять с помощью каких-то эвристик. У авторов она такая чем больше каналов, тем больше ядро. Для 128 каналов ядро будет 3, а для 1024 7. Но как видно из последних двух строчек на таблице выше это не особо влияет на качество.




Проведено сравнение использования разных размеров ядра для 1d свертки vs adaptive. т.к. разница на уровне погрешности, можно остановиться на самом простом случае ядре размера 3. В коде авторов так и сделано, везде захардкожено 3.


Проведено сравнение для задачи детекции. На фоне практически незаметного увеличения количества параметров дает прирост метрик на 1-2%, что выглядит очень убедительно.


Пара практических заметок.
Хотя Conv1d на порядки быстрее, чем две FC в SE блоке, ускорение на практике получается только ~5% потому что самая дорогая операция это GlobalAvgPool, а не последующие свертки.


Проведено сравнение весов для каналов, выученных SE блоком и ECA блоком для 4х разных классов. Прогоняют все картинки этого класса из валидации и записывают среднее для разных каналов. SE выучивает очень похожие attention для разных классов, в том время как у ECA они "have better discriminative ability".


Заметка от автора обзора
Зачем верить авторам на слово, если можно проверить. У меня на Imagenet за 90 эпох обычный SE даёт Acc@1 78.988 Acc@5 94.440, а ECA даёт Acc@1 79.281 Acc@5 94.664. Там была небольшая разница в конфигах обучения SE учился на 4хV100, а ECA на 3хV100, и у них был разный lr. Т.е. не могу пока точно утверждать что ECA > SE, но как минимум не хуже точно, при том что быстрее и практически не добавляет параметров.


2. TAPAS: Weakly Supervised Table Parsing via Pre-training


Авторы статьи: Jonathan Herzig, Pawe Krzysztof Nowak, Thomas Mller, Francesco Piccinno, Julian Martin Eisenschlos (Google, 2020)
Оригинал статьи :: GitHub project :: Colab
Автор обзора: Александр Бельских (в слэке belskikh)


Новая модель от гугла, основанная на BERT, которая парсит таблички в режиме question answering наравне или лучше, чем существующие аналоги, но способна выпонять больше задач + хорошо файнтюнится, что означает, что можно использовать гугловый претрейн для своих задач.




Авторы спарсили большой датасет для претрейна из WikiTable и Infobox, собрав оттуда таблички с различными данными. Модельку завели на основе BERT, добавив туда различных эмбеддингов, специфичных для табличных данных. На вход модель получает последовательность токенов вопроса и табличных данных, а на выходе у неё два классификационных слоя один для выбора ячеек сети (если ответ является просто какой-то ячейкой сети) и один для операции агрегации выбранных ячеек (COUNT, SUM, AVG). Все эмбеддинги токенов комбинируются с наборов специфичных для табличных данных:


  • Position ID индекс токена в табличке (таблица представлена во flatten виде).
  • Segment ID 0 для сегмента с вопросом и 1 для сегмента с табличными данными.
  • Column / Row ID.
  • Rank ID если данные как-то можно упорядочить (дата, число, время) то указывается ранг, как относительный порядок.
  • Previous Answer в некоторых сетапах модель работает в conversational режиме, поэтому добавляют отдельный эмбеддинг, является ли токен аутпутом модели с предыдущей стадии.

Во время инференса выбираются из классификационного слоя ячейки с вероятностью больше 0.5 и над ними проводится предсказанная операция агрегации (NONE, COUNT, SUM, AVG). Претрейн проводится на собранном из WikiTable и Infobox датасете, используется masked language model pre-training objective, как в BERT. Затем модель обучили на датасетах WIKISQL, WIKITQ, SQA, получив выше или на уровне с СОТА-аналогами.


Претрейн проходил на 32 Cloud TPUv3 в течение трёх дней, а файнтюнинг на нужный датасет там же от 10 до 20 часов. Модель примерно такого же размера, как и BERT-large.


Полученная модель позволяет отвечать на вопросы по таблицам, но при этом архитектурно значительно проще существующих аналогов. Более того, она показала хорошие результаты на файнтюнинге под новые схожие данные, что, возможно, станет новым прорывом в работе с табличными данными. Модель на данный момент ограничена тем, что не может процессить слишком большие таблички и не может сформулировать ответ по некоторому сабсету ячеек таблицы. Например, запрос number of actors with an average rating higher than 4 не может быть обработан правильно.




3. DeepFaceLab: A simple, flexible and extensible faceswapping framework


Авторы статьи: Ivan Perov, Daiheng Gao, Nikolay Chervoniy, Kunlin Liu, Sugasa Marangonda, Chris Um, Mr. Dpfks, Carl Shift Facenheim, Luis RP, Jian Jiang, Sheng Zhang, Pingyu Wu, Bo Zhou, Weiming Zhang (2020)
Оригинал статьи :: GitHub project
Автор обзора: Евгений Кашин (в слэке digitman, на habr digitman)


Автор самой популярной репы на гитхабе (14к+ звездочек) по дипфейкам решил закинуть свое творение к академикам и написал статью с кучей "фрилансеров" в авторах. Сам подход достаточно простой и давно известный, но у них настроенные пайплайны, легкая кастомизация, большое комьюнити. Ну и конечно результаты по моему у них на данный момент самые "приятные".


Естественно это подается под соусом "дипфейки это плохо, но лучшая защита это нападение". Что интересно в авторах есть Ctrl Shift Face очень популярные видосы на ютубе с дипфейками, а также Mr. dpfks, который, наверное, делает MrDeepFakes сайт порнхаб с селебами на дипфейках.


Код на TF, но автор написал свой велосипед для TF Leras(Lighter Keras), который вроде проще (куда еще) и быстрее. В любом случае, большинство кто использует сидят на винде и все что им надо создать две папки с картинками двух людей.


Пайплайн из трех частей extraction, training, conversion. Подход ограничен конвертацией "one-to-one" под каждую пару людей нужно все переучивать.


Extraction состоит из:


  • детекции лица и кейпоинтов (S3FD, но можно заменить на RetinaFace);
  • выравнивание лица сглаживают по времени кейпоинты и применяют трансформацию (Umeyama), чтобы привести лицо к нормальному положению;
  • сегментация лица(TernausNet).



Сегментация лица часто не очень точная, поэтому они сделали свою тулзу XSeg которая помогает интерактивно подправить плохие маски и дозакинуть их заново в обучение, такой active learning. Говорят достаточно доразметить 50 фоток руками.


Training. На вход две папки в каждой выровненные лица и маски для отдельного человека. У них два пайплайна, первый DF, по сути простой автоэнкодер. Энкодер и ботлнек (Inter), которые зашарены для двух людей, а также два декодера с разными весами для каждого человека.




Второй LIAE. Энкодер также зашарен, а ботлнека два разных. InterAB генерит эмбединг и для source и для target, а InterB только для target. На вход зашаренному декодеру подается конкат двух эмбедингов. Для source просто конкатится InterAB эмбединг сам с собой, для target InterAB с InterB. Вроде InterAB должен вытаскивать общую для двух доменов инфу, а InterB детали target домена.




Во время "автоэнкодерного" обучения давали разный вес лосам за реконструкцию разных частей лица, например у глаз был самый большой вес. Лоссы: DSSIM + MSE. На гпу обучение пару часов.


Conversion. По сути берется лицо из source и просто прогоняется или через Decoder dst в случае DF или через InterAB и InterB в случае LIAE. Сгенеренное лицо реалайнится по кейпоинтам таргет лица. Результат матчится по цветовой схеме с таргетом одним из 5 алгоритмов на выбор. Блендинг границ лица по сегментационной маске делают через Poisson blending optimization. После этого еще прогоняют результат через суперрез для четкости.




По метрикам конечно сота.




Также есть Ablation Study в котором они тестили немного разные архитектуры, добавление ган лосса и TrueFace. Примеры работы подхода представлены ниже.




4. End-to-End Object Detection with Transformers


Авторы статьи: Nicolas Carion, Francisco Massa, Gabriel Synnaeve, Nicolas Usunier, Alexander Kirillov, Sergey Zagoruyko (Facebook AI, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Андрей Лукьяненко (в слэке artgor, на habr artgor)


Классный новый подход к object detection от facebook! Они предлагают работать с этой с задачей, как с прямым предсказанием сета и использовать трансформер. Базовая модель даёт 42 AP на COCO! Но тренируется 3 дня на 16 V100.


Основная суть DETR заключается в том, то он сразу предсказывает все объекты и тренируется с лоссом, который делает двустороннее соответствие (performs bipartite) между предсказанными боксами и разметкой. Получается, что нам не нужны ни якоря, ни non-maximal supression. Есть один минус: авторы признают, что DETR отлично работает на больших объектах, то хуже на мелких. И для тренировки нужно, цитирую "extra-long training schedule", а также дополнительные лоссы. С другой стороны, подход можно использовать и для других задач, например, сегментации.




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


Object detection set prediction loss
Модель предсказывает N объектов за один раз. Обычно число значительно выше, чем количество реальных объектов. Лосс делает двусторонний матчинг и оптимизирует лоссы для боксов.


В формуле y ground truth, y-hat предсказания. Поскольку "y" меньше размером, то делают паддинг со значениями "no object". По факту ищем пермутации объектов с минимальным костом.


$$display$$\DeclareMathOperator*{\argmin}{arg\,min} \newcommand{\lmatch}[1]{{\cal L}_{\rm match}(#1)} \hat{\sigma} = \argmin_{\sigma\in\Sigma_N} \sum_{i}^{N} \lmatch{y_i, \hat{y}_{\sigma(i)}}$$display$$


Lmatch pair-wise matching cost between ground truth and prediction. Считают с помощью Hungarian algorithm. Он учитывает классы и схожесть между боксами.


Теперь считаем Венгерский лосс для всех пар, которые получились на предыдущем шаге. Для "no object" делим лог-вероятность на 10, чтобы компенсировать дисбаланс классов.


$$display$$\newcommand{\hloss}[1]{{\cal L}_{\rm Hungarian}(#1)} \newcommand{\bloss}[1]{{\cal L}_{\rm box}(#1)} \newcommand{\indic}[1]{1_{\{#1\}}} \hloss{y, \hat{y}} = \sum_{i=1}^N \left[-\log \hat{p}_{\hat{\sigma}(i)}(c_{i}) + \indic{c_i\neq 0} \bloss{b_{i}, \hat{b}_{\hat{\sigma}}(i)}\right]\,,$$display$$


Bounding box loss
Просто использовать L1 не вариант, ибо будут разные масштабы значений для мелких и больших боксов. Поэтому добавляют IoU. Лямбды гиперпараметры. И лосс делят на количество объектов в батче.


$\lambda_{\rm iou}{\cal L}_{\rm iou}(b_{i}, \hat{b}_{\sigma(i)}) + \lambda_{\rm L1} || b_{i} - \hat{b}_{\sigma(i)} ||_1$


DETR Architecture: CNN + transformer + FNN.
Backbone: можно использовать любую. На выходе авторы хотят иметь feature maps с 2048 каналами, высота и ширина картонок в 32 раза меньше оригинальных.




Трансформер.
Энкодер и декодер инвариантны к перестановкам.


Энкодер. Вначале используем 1x1 convolution, чтобы уменьшить количество каналов до d. Поскольку энкодеру надо на вход подавать последовательности, мы преобразуем данные и получаем размерность dxHW. В энкодере используется multi-head attention + FNN. К каждому attention добавляются positional embeddings.


Декодер. Декодирует объекты параллельно в каждом слое. На вход дополнительно подают N эмбеддингов это тренируемые positional encodings, которые добавляются на каждом слое. Им дали название object queries.


На выходе эмбеддинги независимо друг от друга декодируются в координаты боксов и классы с помощью FNN. Благодаря attention модель может учитывать взаимосвязи между объектами.


FNN. Голова просто трехслойный перцептрон. Предсказывает координаты центра боксов и их размеры, линейный слой предсказывает классы с помощью softmax.




Auxiliary decoding losses
В каждом слое декодера добавляют prediction FFNs, параметры которых шарятся, и Hungarian loss. И дополнительно используют layer-norm для нормализации входов в prediction FNN с каждого слоя декодера.


Эксперименты на COCO
Параметры обучения: AdamW, начальный LR трансформера 10^-4, backbone's 10^-5, weight decay 10^-4. Попробовали ResNet-50 and ResNet-101 в качестве backbones модели назвали DETR and DETR-101.


Попробовали ещё улучшить архитектуру: улучшить разрешение с помощью добавления dilation на последней стадии backbone и убирания stride на этой же стадии. Модели назвали DETR-DC5 and DETR-DC5-R101. Требует в 2 раза больше вычислений, но улучшает результаты для мелких объектов.


Scale augmentation поресайзили картинки так, чтобы минимальная сторона была от 480 до 800, а максимальная не больше 1333. Random crop augmentation (+1 AP). И постпроцессинг если модель предсказывает пустые классы, взять следующий класс по вероятности. +2 AP. Обучение: 300 эпох 3 дня на 16 V100. Тренировка на 500 эпох дает + 1.5 AP.




Сравнение с Faster R-CNN
Попробовали улучшить Faster R-CNN:


  • добавить IoU в лосс;
  • random crop augmentations;
  • дольше тренировка.

В таблице выше обычный Faster R-CNN тренировался в 3 раза дольше обычного. Значок "+"означает тренировку в 9 раз дольше (109 эпох). DETR тащит почти все AP кроме AP75 и APs


Ablation
Энкодер по своей сути global scene reasoning и это помогает разъединять объекты. Увеличение количества слоев энкодера и декодера помогает.


FNN внутри трансформера можно интерпретировать как 1 1 convolutional, то есть получается нечто похожее на attention augmented convolutional. Без этого AP падает на 2.3.




DETR for panoptic segmentation
Просто добавляет голову с маской после декодера (бинарно на каждый класс). Но боксы все равно надо предсказывать для лосса.


И классы предсказываются с помощью argmax по каждому пикселю. Так защищаемся от потенциального перекрытия масок разных классов.





И последнее картинка про качество, для тех, кто очень обрадовался. Чем больше объектов, тем хуже работает модель.




5. Language Models are Few-Shot Learners


Авторы статьи: Tom B. Brown et.al. (OpenAI, 2020)
Оригинал статьи :: GitHub with examples and statistics
Автор обзора: Вадим Петров (в слэке graviton, на habr belgraviton)


До сих пор, использование предобученных трансформеров в прикладных задачах (например, questions answering) требовало дообучения. Большая группа ученых из OpenAI продемонстрировала, что при увеличении размера языковой модели GPT-3 (до 175B весов), достигается хорошая точность на специфических задачах без дообучения, сравнимая с моделями, которые файнтюнились на них (см. график ниже). Для задачи генерации новостей достигнуто качество, сложно отличимое от новостей, написанных людьми.


Авторы изучали модель применительно к разным задачам на основе подходов zero-shot, one-shot и few-shot. Случай дообучения под задачи они оставили на будущее. Для случая few-shot на графике снизу видно значительное увеличение точности при росте числа параметров модели.




Авторы пытались решить следующие задачи:


  1. Специфичные задачи в NLP требуют сбора датасетов под них. Это иногда довольно затратно.
  2. Решение проблемы с генерализацией под новые задачи, где данных может быть слишком мало для больших моделей трансформеров.
  3. Люди требуют очень мало информации для решения смежных NLP задач. Хорошие NLP модели должны также демонстрировать аналогичное поведение.

Архитектура
Использована архитектура GPT-2 с модифицированной инициализацией, преднормализацией и обратимой токенизацией. Отличием является использование плотных и локально разреженных "attention patterns" в слоях трансформера. Обучено 8 моделей от 125M до 175B параметров.




Замечу, что архитектура GPT-2 тоже лишь незначительно отличается от GPT-1, которая представлена ниже.




Тренировка
Были использованы 5 датасетов: Common Crawl, WebText2, Books1, Books2 и Wikipedia. Всего около 300 млрд токенов.


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


Использован Adam, с ограничением градиента в 1.0, cosine learning rate decay и warmup. Обучение GPT-3 заняло 3640 PetaFlops-days на кластере из V100 GPUs, предоставленном Microsoft.


Результаты


Тестирование проводилось на большом наборе датасетов. В большей части из них удалось с помощью few shot подхода получить результаты схожие с fine tune SOTA подходами. Примером, такого случая является перевод, результаты для которого представлены в таблице ниже. При этом, для нескольких задач удалось достичь даже значительного улучшения SOTA. Об этом ниже.




На задаче предсказания последнего слова в параграфе SOTA улучшена на 8 %, а в тесте с ответами на вопросы о физических процессах модель превзошла предыдущую SOTA (fine-tuned RoBERTa) на 1% даже в zero-shot режиме!





Арифметические операции


Для задачи выполнения арифметических операций сгенерировали датасет, на котором продемонстрировали способность модели (few-shot) решать данную задачу с точностью больше 90% для 2-х и 3-х значных чисел. Датасет обещают выложить.


Генерация новостей
Анализировался режим few-shot. Модели для генерации новости показывалось 3 новости по выбранной теме и заголовок с подзаголовком для новой статьи. Качество статей проверялось 80 людьми. Точность идентификации источника новостей заметно снижается при увеличении модели и достигает для GPT-3 только 52%, что очень близко к уровню случайного выбора (50%) несмотря на то, что люди тратили больше времени на оценку результатов больших моделей.




Имеющиеся проблемы


  • В то же время разработчики нашли ряд задач, в которых модель была неуспешна (оценка связи двух выражений -ANLI dataset, сжатие текста RACE, QuAC).


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


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



6. TabNet: Attentive Interpretable Tabular Learning


Авторы статьи: Sercan O. Arik, Tomas Pfister (Google Cloud AI, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Александр Бельских (в слэке belskikh)


Работа от Google, в которой представлена архитектура нейросети для табличных данных, превосходящая доминирующие до этого подходы на ансамблях деревьев, сохраняя свойства интерпретируемости и легковесности. Дополнительно обладает возможностью предобучения в режиме self-supervising, что открывает большие возможности для дообучения и обучения на маленьких датасетах.


В отличии от tree-based подходов, на вход TabNet поступают сырые табличные данные, а обучается она через обычный градиентный спуск, выучивая хорошие репрезентации данных.


В архитектуре использован sequential attention механизм, который определяет, какие признаки будут использованы во время текущего decision step, что позволяет получить интерпретируемость предсказания.


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




Дискретные признаки классически приводятся к виду таблицы выучиваемых эмбеддингов. Сами признаки прогоняются через специальный модуль feature transformer (ничего общего с архитектурой Transformer не имеет).


В режиме self-supervised pretraining модель учится предсказывать пропущенные признаки из таблицы входных данных, где эти признаки случайным образом маскируются.




Модель показала себя наравне или лучше чем текущие SOTA модельки для табличных данных.





Ссылка на начало.

Подробнее..

Нет времени объяснять, сделай автопилот

05.08.2020 14:08:45 | Автор: admin
image

Здравствуйте, товарищи!
На выходных проходил хакасборкатон гонки на самоуправляемых моделях автомобилей на базе комплекта donkeycar при содействии Х5 и FLESS.
Задача заключалась в следующем: сначала надо было собрать машинку из запчастей, затем ее обучить проходить трассу. Победитель определялся по самому быстрому прохождению 3 кругов. За наезд на конус дисквалификация.

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

Когда мы собирались на это соревнование, сразу было понятно, что будет очень весело и очень сложно, ведь нам давалось всего 5 часов с учётом перерыва на обед чтобы собрать машинку, записать датасет и обучить модель.

Ослик-машинка


Donkeycar состоит из корпуса, на который крепится камера с широкоугольным объективом (170 град), Raspberry Pi3+, платы управления сервоприводами, софт и вообщем-то всё. Но как оказалось впоследствии, сборка даже такого простого аппарата в условиях ограниченного времени и рандомных глюков оборудования может затянуться, и вы не успеете.
image

Сборка


Соревнование началось с того, что сначала надо было разобрать машинку и собрать её снова. Надо отдать должное организаторам, нам не предложили собирать непонятную кучу деталей с нуля, а дали возможность разобраться в устройстве на готовом примере. Мы сэкономили массу времени, сделав фотки всех соединений, и собрали машинку обратно минут за 10 =)
image
image
image
image

Подключение к машинке и проверка работы


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

Мы решили не скучать и подключиться по Ethernet кабелю, который вместе с остальным барахлом всегда у меня валяется в рюкзаке. Почему-то на машинке то ли не было DHCP сервера, то ли он не работал, то ли вообще он там не должен был быть, и мы смекнули, что wireshark запросто достатнет source ip по broadcast при подключении кабеля к Raspberry. Так и получилось, но зайдя на машинку, мы потратили довольно много времени пытаясь заставить вайфай работать. В конечном итоге всем участникам скинули специальный файл, где находился конфиг.

Калибровка шасси и подключение джойстика


image
Подключение джойстика у нас заняло примерно 35 минут, пока мы читали доки и сканировали bluetooth, пытаясь сопрячь машинку и джойстик. Оказалось, что проблема в том, что в помещении было слишком много джойстиков и они случайным образом сопрягались с машинками коллег по гонкам было очень весело обнаружить, что ты управляешь шасси случайной машинки =)

На следующем этапе требовалось откалибровать steering и throttle, то есть PWM на поворот и газ. Это был один из самых важных параметров, требовалось сделать так, чтобы значение соотносилось со скоростью движения машинки и модель справлялась с управлением.
image

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

Сбор данных и обучение модели


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

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

Так же мы добавили albumentations как аугментации и постарались навалить их как можно больше!
В этом форке я злостно захардкодил тяжёлые аугментации с конвертом из pil и обратно это потребовало еще пересобрать окружение для машинки, что отразилось на времени.

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

Первая модель проехала 3 круга с ошибками и на 4 вылетела с трассы. После этого мы потеряли еще минут 20, потому что забыли вставить в машинку SD-карту.

Окончательная модель была обучена на 19 тыс. картинках с кастомными аугментациями и чисткой данных.
image

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

Далее графики первой и второй модели с лучшим значением MSE loss 0.093 и 0.086 соотвественно.
image
image
Кажется, что второй график выглядит получше!

Из видео понятно, что мы плохо откалибровали steering и слабенько почистили датасет, но нам этого хватило =)


Видео с GoPro, которое мы записали уже после основного старта:


Финал


Мы первые были готовы начинать заезд и пошли к трассе, но там нас ждала неудача, вайфай постоянно отваливался, нас чуть не сняли с соревнования. И вот, когда уже почти был дан старт, машинка вдруг начала ехать назад. Видимо, я что-то напутал при калибровке throttle =)

Но ничего, под хохот всего зала она поехала вперёд и достойно держалась кругов 8 или 9 на трассе, сильно петляя, но всё равно принесла нам заслуженную победу!


Стараюсь не смотреть в кадр =)
image

image

Благодраности

Спасибо сообществу ods.ai, без него невозможно развиваться! Огромное спасибо товарищам по команде: Вале Бирюковой, Егору Урванову(Urvanov), Роме Дербаносову(Yandex). Ждем с нетерпением видео обзора от Виктора Рогуленко(FLESS).

p.s. Отдельное спасибо Вале Бирюковой, которая, к сожалению, за день до соревнований свалилась с температурой 38.5, но очень помогла ссылкой.

Aurorai, llc
Подробнее..

Рубрика Читаем статьи за вас. Июнь 2020 года

19.08.2020 14:16:03 | Автор: admin


Привет, Хабр! Продолжаем публиковать рецензии на научные статьи от членов сообщества Open Data Science из канала #article_essense. Хотите получать их раньше всех вступайте в сообщество!


Статьи на сегодня:


  1. PointRend: Image Segmentation as Rendering (Facebook AI Research, 2020)
  2. Natural- To Formal-Language Generation Using Tensor Product Representations (USA, 2019)
  3. Linformer: Self-Attention with Linear Complexity (Facebook AI, 2020)
  4. DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolution (Johns Hopkins University, Google, 2020)
  5. Training Generative Adversarial Networks with Limited Data (NVIDIA, 2020)
  6. Multi-Modal Dense Video Captioning (Tampere University, Finland, 2020
  7. Are we done with ImageNet? (DeepMind, 2020)


1. PointRend: Image Segmentation as Rendering


Авторы статьи: Alexander Kirillov, Yuxin Wu, Kaiming He, Ross Girshick (Facebook AI Research, 2019)
Оригинал статьи :: GitHub project
Автор обзора: Евгений Желтоножский (в слэке evgeniyzh, на habr Randl)


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




Мотивация авторов приходит из рендеринга, где подобные проблемы решаются с помощью нерегулярного семплирования. На проблему сегментации предлагается посмотреть как на проблему рендеринга: мы пытаемся получить из (непрерывного) occupancy map предмета или класса "рендерить" регулярную сетку (пикселей) маски сегментации. PointRend берет маску низкого разрешения, апсемплит и уточняет ее в определенных точках. Так как большая часть маски не требует уточнения, эти точки расположены в основном на границе маски. Таким образом, для увеличения разрешения маски в два раза мы не классифицируем в четыре раза больше пикселей.


Во время инференса используется техника, которая называется adaptive subdivision. Для начала feature map апсемплится стандартным билинеарным апсемплингом. Далее, N точек с самой близкой к 0.5 вероятностью принадлежности к маске прогоняются через MLP (с общими весами для всех точек и регионов) и для них генерируются новые фичи. Процесс повторяется пока не достигается необходимое разрешение, и требует N * log (M/M_0) предсказаний вместо M^2 (M входной размер, M0 размер первого шага, N количество обрабатываемых граничных точек).




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




В качестве фич для точек используется конкатенация высокоуровневых фич (предсказание сети о классе этой точки) и низкоуровневых (фичи из одного или нескольких фичермапов CNN).


Для экспериментов авторы использовали Mask R-CNN с ResNet-50 + FPN. Голову для предсказания масок заменили на более эффективную которая предсказывает маску 7x7. Кроме того, на вход масочной головы во время трейнинга подавали выход головы для bounding box, что не улучшило Mask R-CNN, но улучшило PointRend за счет более качественного семплирования точек. В итоге оверхед по флопсам по сравнению с Mask R-CNN с масками 28x28 почти в 2 раза (0.5 vs. 0.9 GFLOPS), но конечно не сравним с масками 224x224 (34 GFLOPS).


Так как PointRend улучшает качество масок на границах, значительного улучшения по AP не наблюдается. Но на датасете с более точными масками (LVIS) профит выше. Авторы провели неплохой ablation study: количество точек на каждом этапе (N), итоговое разрешение маски, тип семплирования во время тренинга, а также разные архитектуры и увеличение времени тренировки.




Алгоритм также протестировали на семантической сегментации, поверх DeeplabV3 и SemanticFPN. Опять таки, по mIoU профит небольшой, но сетка восстанавливает мелкие детали и визуально разница заметна.




2. Natural- To Formal-Language Generation Using Tensor Product Representations


Авторы статьи: Kezhen Chen, Qiuyuan Huang, Hamid Palangi, Paul Smolensky, Kenneth D. Forbus, Jianfeng Gao (USA, 2019)
Оригинал статьи :: GitHub project :: Реализация автора обзора
Автор обзора: Максим Плевако (в слэке Max Plevako)


Исследователи из компании Майкрософт предлагают модель кодера-декодера на основе представлений в виде тензорных произведений для перевода естественного языка в формальный.


Кодер использует представления в виде тензорных произведений для погружения символических структур некоторой формальной задачи, сформулированной на естественном языке, в линейное векторное пространство. На основе этих векторных представлений декодер, по сути, генерирует символическую формулу/программу, решающую поставленную задачу. Авторам удалось существенно превзойти результаты ранее существовавших моделей на основе долгой краткосрочной памяти (LSTM) и показать передовые результаты в решении математических задач на основе набора данных MathQA и синтезе программ на основе набора данных AlgoLisp.




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


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


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




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


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




Такая модель, обученная с использованием метода адаптивной оценки моментов с педагогическим принуждением и перекрёстной энтропией в качестве функции потерь, показала на наборе данных MathQA точность операций/численных результатов, равную 71.89% и 55.95% соответственно. В задаче синтеза программ на наборе данных AlgoLisp также обученная модель показала точность 84.02% и 93.48% на полном и очищенном наборах тестов соответственно.




Примеры выводов:




3. Linformer: Self-Attention with Linear Complexity


Авторы статьи: Sinong Wang, Belinda Z. Li, Madian Khabsa, Han Fang, Hao Ma (Facebook AI, 2020)
Оригинал статьи
Автор обзора: Андрей Лукьяненко (в слэке artgor, на habr artgor)


Авторы осознали, что механизм self-attention можно аппроксимировать матрицей низкого ранга. Они предлагают новую архитектуру self-attention, которая уменьшает сложность алгоритма с O(N^2) до O(N) во времени и пространстве.


Прям супер эффективно. Но все равно использовали 64 V100 для тренировки модели.


Если по сути: scaled dot-product attention декомпозируется во много мелких attention с помощью линейных проекций, комбинация которых по факту дает low-rank factorization от оригинального attention.


Self-Attention is Low Rank
P the context mapping matrix. Авторы берут RoBERTa-base и RoBERTa-large, которые были претренированы на задачах классификации и masked-language-modeling tasks. Применяют SVD на головы и слои модели и строят графики нормализованных кумулятивных сингулярных значений, усредненных по 10к предложений. Как видно, большую часть информации можно получить, взяв несколько первых больших сингулярных значений.




P можно аппроксимировать матрицей низкого ранга, но для этого придется делать SVD в каждой матрице self-attention, поэтому авторы предлагают другую идею.


Model
Основная идея: при расчете ключей и значений мы добавляем две матрицы линейных проекций. Они берут матрицы KW и VW (размерность n x d) и проецируют в размерность k x d, а затем считают n x k матрицу P с помощью scaled attention.




Дополнительные способы увеличения эффективности:


  • Шеринг параметров между проекциями: Headwise, layerwise or key-value.
  • Различная размерность проекций для разных слоёв. Для верхних слоёв можно уменьшать размерность без особых потерей качества.
  • Другие варианты проекций например pooling или convolution с кернелом n и stride k.

Эксперименты
RoBERTa. 64 Tesla V100 GPUs и 250k итераций. Во-первых, мы видим, что перплексия на валидации лишь чуть-чуть ниже, чем у трансформера. Дальше мы видим, что с увеличением длины последовательности модель сходится примерно к такой же перплексити.


Fine-tuning даёт примерно такое же качество, иногда и выше.




Ну и самое главное инференс быстрее и требует меньше памяти




Для любителей математики в статье есть теоремы и их доказательства.


4. DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolution


Авторы статьи: Siyuan Qiao, Liang-Chieh Chen, Alan Yuille (Johns Hopkins University, Google, 2020)
Оригинал статьи :: GitHub project :: sotabench
Автор обзора: Евгений Желтоножский (в слэке evgeniyzh, на habr Randl)


Новая сота в object detection (54.7% AP на COCO test-dev), instance (47.1% AP на COCO test-dev) и panoptic segmentation (49.6% PQ на COCO test-dev). Основные идеи добавление рекуррентности в Feature Pyramid, добавление аналога SE для глобального контекста и смешивания конволюций с разным dilation (который авторы называют atrous), но (частично) пошаренными весами.


Recursive Feature Pyramid (RFP)Switchable Atrous Convolution предлагает прогонять изображение по пирамиде несколько раз (в статье авторы ограничиваются двумя), каждый следующий раз подмешивая результаты предыдущего.




В частности, для каждой из 4 частей ResNet, в первый блок подмешиваются фичи, полученные по следующей схеме (Atrous Spatial Pyramid Pooling): фичи подаются на вход 4 блокам с выходом того же разрешения и 1/4 каналов каждый, три из которых это конволюция (1 1, 3 3 c dilation 3, 3 3 c dilation 6) + ReLU, а последний это global average pooling + конволюция(1 1) + ReLU. Выходы конкатенируются и складываются с выходом первого блока.




Кроме того, на выходе фичи t+1-ой пирамиды смешиваются с фичами t-ой пирамиды с весами полученными через attention ().




Switchable Atrous Convolution (SAC)
На уровне отдельных операций авторы предлагают заменить стандартные конволюцию блоком из двух конволюций с общими весами и разным dilation (на практике авторы выучивают разницу w между весами, которая добавляет 0.1% к перформансу, но использование независимых весов все ломало). Эти конволюции складываются с весами, посчитанными еще одной 1*1 конволюцией. До и после конволюции авторы добавляют некий упрощенный аналог SE блока, но без нелинейности.




Как уже упоминалось, предложенный метод получает соту в detection, instance и panoptic segmentation. Авторы постарались повторить как можно точнее экспериментальный сетап HTC.




Также проведен подробный ablation study. RFP и SAC добавляют 4.2 и 4.3 к AP детекшна на ResNet-50 соответственно, вместе добавляя 7%. Так же проверены индивидуальные элементы RFP и SAC.


Авторы визуализируют веса конволюции c dilation 3 в блоке SAC. Они замечают что эта конволюция получает вес на больших объектах, в то время когда на малых больший вес у конволюции c dilation 1 (впрочем, судя по сотабенчу, AP на мелких объектах у DetectoRS несколько ниже чем у того же EfficientNet).




5. Training Generative Adversarial Networks with Limited Data


Авторы статьи: Tero Karras, Miika Aittala, Janne Hellsten, Samuli Laine, Jaakko Lehtinen, Timo Aila (NVIDIA, 2020)
Оригинал статьи
Автор обзора: Евгений Кашин (в слэке digitman, на habr digitman)


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




Проблема с маленькими датасетами дискриминатор быстро переобучается. На больших датасетах это не является проблемой (как говорят в BigGAN роль D прокидывать сигнал, а не обобщать). На графике ниже видно, как влияет объем данных на обучение, чем меньше тем хуже Frchet inception distance (FID). Сравнивая (b) и (с) видно, что на меньшем объеме, распределение выходов дискриминатора D очень быстро перестает пересекаться для real и fake, а распределение на валидационных данных становится близко к fake оверфиттинг.




Простое применение на исходном датасете аугментаций не подходит для генерации изображений, т.к. тогда эти аугментации "утекают" и генератор начинает генерировать с этими аугментациями. Предложенная ранее Consistency regularization, суть которой в сближении выходов D для аугментированных и неаугментированных картинок, тоже приводит к утеканию аугментаций. Дискриминатор становится "слеп" к аугментациям и генератор этим пользуется.


Авторы предлагают использовать аугментации перед дискриминатором всегда. Для реальных и сгенерированных изображений. Получается D никогда не увидит реальных изображений. А генератор G должен генерировать такие семплы, которые после аугментаций будут выглядеть как настоящие картинки после аугментаций. Хорошо видно на 2(b).




Самое интересное не все аугментации подходят, а только те, которые генератор может неявно "отменить". Они называют их non-leaking. Но это не значит, что каждая отдельная аугментация должна быть отменяемой, а это больше про вероятностный смысл. Поэтому зануление 90% изображения отменяемая (применив его много раз случайно, можно догадаться, какое было исходное изображение), а случайный поворот на [0, 90, 180, 270] неотменяемый (после аугментации не угадать начальное положение картинки). Но многие аугментации становится возможно использовать, если применять их с вероятностью p < 1. Например, тот же случайный поворот, применяемый с p=0.5, будет чаще выдавать картинку в 0 градусов. Поэтому можно будет догадаться, какая картинка была до аугментаций(опять же, в вероятностном смысле, а не по одной картинке).


Они пробовали геометрические(повороты, смещения) и цветовые трансформации, добавление шума, cutout, частотные фильтрации. Важно, что т.к. аугментации используют после G и перед D в обучении, они должны быть дифференцируемые. Чаще всего композиция non-leaking аугментаций тоже non-leaking. Они применяют аугментации последовательно в одном порядке, каждую с равной для всех вероятностью p. Даже с небольшим значением p финальная картинка почти всегда будет аугментированной 2(с). Поэтому в любом случае, генератору нужно стараться делать картинки максимально дефолтными, без аугментаций. Течет или нет аугментация также зависит от вероятности p. Примеры для отдельных аугментаций(зависимость от p).




Остается проблема, что для каждого датасета и объема данных надо было бы подбирать p. Поэтому они предложили это делать адаптивно, по эвристике, меряющей величину оверфиттинга. Два варианта эвристики (0 не оверфиттинг, 1 оверфиттинг):


  • первая использует валидационный сет (неудобно): r_v = (E[Dtrain]-E[Dval])/(E[Dtrain]-E[Dgen]);
  • вторая только выход D (доля положительных выходов D): r_t = E[sign(Dtrain)].

Каждые 4 батча обновляют значение величины аугментаций p по выбранной эвристики. Если эвристика показывает, что сильное переобучение, то прибавляют p, и наоборот. Назвали adaptive discriminator augmentation(ADA).




Видно, что по сравнению с первым изображением, использование ADA уменьшает оверфиттинг со временем, а градиенты в G становятся четче.По метрикам и визуально результаты лучше, чем у бейзлайнов на разных по объему датасетах. Их sample-efficiency позволяет применять StyleGAN2 на новых доменах с всего лишь 1к картинок.


Также показали, что можно использовать их метод для transfer learning. Он значительно ускоряет процесс обучения и вероятность что-то вообще выучить.


Предобученные веса на FFHQ. Кода нет, но есть псевдокод для используемых аугментаций.


6. Multi-Modal Dense Video Captioning


Авторы статьи: Vladimir Iashin, Esa Rahtu (Tampere University, Finland, 2020)
Оригинал статьи :: GitHub project
Автор обзора и статьи: Владимир Яшин (в слэке vdyashin)


Что такое (Dense) Video Captioning?
Начнем с того, что такое Video Captioning. У нас есть видео и наша задача описать текстом, что происходит на видео. Проблема с таким подходом в том, что сложно описать одним предложением 120 минутный фильм. Поэтому подход сейчас состоит в том, чтобы находить "интересные" моменты на видео, а потом описывать только их. Отсюда и название Dense Video Captioning.




Что нового мы предлагаем?
Давайте подумаем как человек воспринимает информацию с видео. Мы ведь не только смотрим на картинку, но еще и слушаем аудио. А если плохо знаем иностранный язык, то еще включаем субтитры. Несмотря на это, бОльшая часть предыдущих работ использует только визуальную информацию. А те, кто использует аудио или субтитры, показывают слабые результаты или используют датасеты, где субтитры довольно точно описывают, что происходит на видео (типа "How to do ..."). В нашей работе мы показываем важность дополнительных модальностей (аудио и речь) на датасете с открытым domain в решении задачи Dense Video Captioning.


Метод
Как обычно подходят к решению задачи Dense Video Captioning? Сначала тренируют event localization модуль, а потом используют seq-to-seq модель для генерации описания для каждого из предсказанных временных интервалов.


Event Localization
Event localization можно представить как детектор на картинках только по времени. В качестве event localization модуля мы взяли ранее представленную двунаправленную LSTM, которая за первый проход (forward) для каждой фичи в последовательности накидывает anchors и выдает уверенность в том, что event там есть. Так как LSTM аккумулирует только предыдущую информацию, используется еще и обратный проход по фичам (backward). Опуская детали, получаем много возможных временных интервалов (proposals), из которых выбираем наиболее уверенные и используем их дальше для генерации описания.


Caption Generation
Этот модуль принимает на вход фичи, соответствующие временному интервалу. В нашем случае фичи из I3D, VGGish и тренируем текст эмбеддинг для речи. В качестве seq-to-seq модели, взяли ванильный трансформер.




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




Эксперименты и что получилось
В качестве датасета использовали ActivityNet Captions. Сравнивали с другими ребятами и получили, что наш метод, как минимум, так же хорош как и СОТА при этом мы тренировались только на 90% от датасета, потому что 10 % уже удалились с ютюба (см. таблицу). Можно еще посмотреть на черрипикнутый примерчик в статье.




Что забрать с собой домой


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

От автора обзора про библиотеку: мне показалось мало и я решил начать делать небольшую либку для рассчета фичей для видео. Что классного в либке? То что можно взять список видео в формате .mp4 и запараллелить на всех GPU что у вас есть, и пойти слак дальше читать. Пока поддерживается только I3D (с PWC-Net для optical flow) и VGGish модельки.


7. Are we done with ImageNet?


Авторы статьи: Lucas Beyer, Olivier J. Hnaff, Alexander Kolesnikov, Xiaohua Zhai, Aron van den Oord (DeepMind, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Евгений Желтоножский (в слэке evgeniyzh, на habr Randl)


Авторы задают вопросы: "есть ли смысл выжимать 0.1% на имеджнете за 10 миллионов GPU-часов", "насколько хорошо обобщаются новые модели на ImageNet и насколько мы просто оверфиттимся на лейблы"? В частности предлагается новая разметка валидации ImageNet, показывается что люди предпочитают предсказания сетей оригинальным лейблам.




Какие вообще проблемы есть у лейблов ImageNet?


  • Один лейбл на изображение, где иногда больше чем один объект.
  • Процесс предложения лейблов сильно ограничивает разметчиков: их спрашивают есть ли объект на картинке, хотя иногда есть более подходящий лейбл.
  • Есть практически дублирующие классы: sunglasses и sunglass, laptop и notebook, или projectile, missile и missile.



Авторы начинают со сбора вероятных лейблов для каждого из валидационных изображений. Для этого они взяли 19 моделей (VGG-16; Inception v3; ResNet-50; ResNet-152; ResNeXt-101, 32x8d; ResNeXt-101, 32x8d, IG; ResNeXt-101, 32x48d, IG; BiT-M; BiT-L; Assemble ResNet-50; Assemble ResNet-152; NASNet-A Large; NASNet-A Mobile; Once for all (Large); S4L MOAM; CPC v2, fine-tuned; CPC v2, linear; MoCo v2, long; SimCLR). Для каждой модели и каждой пары картинка-лейбл посчитали логит и вероятность. Взяли 150000 самых больших логитов и самых больших вероятностей. После этого выкинули пары, которые предложила только одна модель. Добавили топ-1 предикт каждой модели и оригинальный лейбл из ImageNet. Чтобы уменьшить количество пропозалов, 256 картинок разметили 5 экспертов, и оставили только модели которые дали Recall выше 97% (VGG-16; Inception v3; BiT-M; BiT-L; CPC v2, fine-tuned), уменьшив среднее количество лейблов на картинку с 13 до 7.4.


Далее, лейблы по которым не все модели были согласны (а таких было 24 889) переразметили люди. Картинки для которых было слишком много пропозалов (больше 8 ), разбили на несколько заданий, получив в итоге 37 998 задач. Каждую задачу решило 5 независимых экспертов.


Для объединения предсказаний использовался метод, который оценивает качество разметчика с помощью maximum-likelihood. Для животных, где часто нужна экспертиза, оригинальный лейбл добавили как еще одного виртуального разметчика. В итоге, получили 57 553 лейблов для 46 837 картинок, оставшиеся картинки выкинули. Эти лейблы назвали "ReaL labels" и использовали для оценки моделей.


Для начала сравнили точность на оригинальных и на ReaL лейблах. Довольно явно выявилось 2 тренда: до ~81% коэффициент корреляции равен 0.86, а после 0.51. Z-test на то, что коэффициенты разные дал p<0.001. Видимо, топовые модели начинают оверфититься на разметку ImageNet. Кроме того, топовые модели получили точность на ReaL лейблах выше чем оригинальные лейблы.




Чтобы подтвердить это утверждение, авторы взяли лейблы на которых модели не согласны с разметкой и спросили людей, какой лейбл больше подходит картинке. Топовые модели BiT-L и NoisyStudent-L2 люди посчитали лучше оригинальной разметки. Также авторы взяли ансамбль трех топовых моделей: NoisyStudent-L2; BiT-L; Fix-ResNeXt-101, 32x48d, IG. Получили 89.03% на оригинальных лейблах и 91.20% на ReaL.


Заодно проверили, попадают ли топ-2 и топ-3 предикты в список допустимых лейблов. Точность второго и третьего предикта значительно ниже, но все равно довольно высока и коррелирует с точностью на ReaL.


Следующий вопрос: как ведут себя модели на картинках с множественными объектами или одним из дублирующих лейблов? Предсказывается ли рандомно один из лейблов или модель выучивает bias разметчиков? Авторы выбрали неоднозначные классы как те, на которых оракул который предсказывает рандомный лейбл из ReaL получает меньше 90%. Таких классов получилось довольно много (253): часть неоднозначные: (sunglass, sunglasses), (bathtub, tub), (promontory, cliff), (laptop,notebook); часть часто находящиеся на одном изображении: (keyboard, desk), (cucumber, zucchini), (hammer, nail).


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




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


По пути авторы попробовали улучшить трейнинг. Во первых, они заменили softmax на sigmoid. Во вторых на 10-fold с помощью BiT-L почистили трейнинг сет (дропнув ~10% лейблов). Получили улучшение на 0.5-2% относительно baseline.


Результаты разных моделей на оригинальной и ReaL валидациях в таблице ниже.


Подробнее..

Рубрика Читаем статьи за вас. Июль август 2020 года

14.10.2020 14:07:29 | Автор: admin


Привет, Хабр! Продолжаем публиковать рецензии на научные статьи от членов сообщества Open Data Science из канала #article_essense. Хотите получать их раньше всех вступайте в сообщество!


Статьи на сегодня:


  1. High-Resolution Neural Face Swapping for Visual Effects (Disney Research Studios, ETH Zurich, 2020)
  2. Beyond Accuracy: Behavioral Testing of NLP Models with CheckList (USA, 2020)
  3. Thieves on Sesame Street! Model Extraction of BERT-based APIs (UMass & Google Research, ICLR, 2019)
  4. Time-Aware User Embeddings as a Service (Yahoo! Research, Temple University, 2020)
  5. Are Labels Necessary for Neural Architecture Search? (Johns Hopkins University, Facebook AI Research, 2020)
  6. GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding (Google, 2020)
  7. Data Shapley: Equitable Valuation of Data for Machine Learning (USA, 2019)
  8. Language-agnostic BERT Sentence Embedding (Google AI, 2020)
  9. Self-Supervised Learning for Large-Scale Unsupervised Image Clustering (Technion, Israel, 2020)
  10. Batch-Channel Normalization and Weight Standardization (2 papers, Johns HopkinsUniversity, USA, 2019)


1. High-Resolution Neural Face Swapping for Visual Effects


Авторы статьи: J. Naruniec, L. Helminger, C. Schroers and R.M. Weber (Disney Research Studios, ETH Zurich, 2020)
Оригинал статьи
Автор обзора: Александр Широносов (в слэке shiron8bit, head of ml at Dowell/Everypixel)


Исследователи из disney research предложили ряд улучшений для часто используемого Y-shaped автоэнкодера в задаче замены лиц (face swap), которые позволили им работать с изображениями размером 1024x1024, показывая при этом качество лучше, чем у распространенных в этой области подходов (у deepfacelab [DFL] в частности).


Введение
Авторы четко отделяют задачу face swapping от часто появляющейся рядом задачи face reenactment в первом случае лицо персоны из source видео мы переносим в визуальные условия персоны на target-видео, ну и собственно все поведение и эмоции задаются target-персоной, а во втором случае по эмоциям из source мы анимируем персону/лицо из target (которое может задаваться как видео, так и фото в случае с one-shot методами). Задача замены лиц периодически возникает в киноиндустрии, когда нужно оживить уже мертвого актера, омолодить еще живого, да и в случаях с использованием дублеров/каскадеров, при этом сейчас она решается зачастую при помощи трудозатратного и дорогого cgi (computer-generated imagery), поэтому интерес диснея здесь не случаен.


Пайплайн и архитектура
Авторы, как и в DFL, используют идею из работы YAN, SHUQI, HE, SHAORONG, LEI, XUE, et al. Video Face Swap Based on Autoencoder Generation Network, в которой была предложена идея Y-shaped архитектуры нейросети, состоящей из одного энкодера, переводящего изображения в некое общее для двух персон латентное пространство, и двух декодеров, каждый из которых умеет генерировать только одну персону. Таким образом, в латентное пространство сетка пытается закодировать множество эмоций, а распутывание (disentanglement) персон происходит физически при помощи разных декодеров. Однако, в отличие от DFL (широко используемой в нем Stylized autoencoder/SAE-архитектуры), авторы текущей работы предлагают использовать comb-подход с более чем двумя декодерами. Конкретно в экспериментах брали 8 декодеров, которые восстанавливали 6 персон (для 2 персон было по 2 декодера для разных target-видео).



При этом сам пайплайн замены лиц стандартный: вырезаем из кадра target-лицо и выравниваем его, подаем на энкодер, получившийся латентный код подаем на декодер той персоны, которую пересаживаем на target, получаем соответствующее по эмоции и прочему appearance лицо из source, делаем обратное выравнивание, пересаживаем итоговое лицо (не забывая блендить).



Улучшения и тренировка
Авторами были предложены следующие трюки для улучшения качества работы модели:


  1. Для обучения автоэнкодеров до разрешения аж 1024 по аналогии с ProGAN/StyleGAN1 используют progressive-обучение, адаптированное под автоэнкодеры: стартуют с разрешения 4x4, на каждом шаге к энкодеру и декодеру добавляют по блоку, работающему с разрешением в два раза большим (с соответствующими энкодеру/декодеру даунсэмплингу и апсэмплингу). Поскольку эти блоки в финальной сетке будут находиться где-то внутри, добавляют еще to_rgb/from_rgb свертки, которые нужны для адаптации инпутов и для подсчета функции потерь на промежуточных этапах. Чтобы не шокировать архитектуру новыми блоками с рандомными весами, используют фейдинг, при котором картинка создается из смеси с весами alpha и 1-alpha выхода с нового слоя и увеличенного в 2 раза выхода с предыдущего (уже обученного) слоя. При этом в процессе обучения нового блока коэффициент alpha увеличивается от 0 до 1, а вместе с ним и влияние этого блока.
  2. При обучении использовали свой датасет из снятых 4K-видео c 9 добровольцами, при обучении каждого нового слоя предъявляли по 10^5 изображений каждой персоны. Само обучение представляет из себя реконструкцию каждым декодером своей персоны, в качестве функции потерь на всех уровнях, кроме двух самых последних/больших, бралась SSIM, а на двух последних MS-SSIM. При этом подсчет ведется только по маске target-лица, которая получается зачастую небольшим расширением контура, возвращаемого детектором лэндмарок (чтобы брови тоже влезли).
  3. Большинство детекторов лэндмарок обучалось на не очень больших изображениях, да и точность их проверяется зачастую на отдельных изображениях, что в случае с последовательностью high-res кадров может приводить к скачкам в соседних кадрах и к заметному мерцанию в итоговом видео. Авторы предлагают решить это усреднением предсказаний лэндмарок по n=9 смещенным версиям исходного bounding boxа с лицом (смещения делаются по горизонтальное оси, по сути версия tta).
  4. Наконец, различия в цвете и освещении между source и target видео может приводить к заметным швам (seams) в месте наложения нового лица по маске, не говоря уже о различиях между внутренней частью лица и внешней. Зачастую эту проблему решают применением пуассоновского блендинга (т.н. seamless blending), но он тоже спасает далеко не всегда. Авторы предлагают модифицированный вариант multi-band blending, при котором для смешиваемых изображений строятся пирамиды Гаусса и Лапласа (по сути набор задаунсэмпленных изображений и разниц/граней, по которым можно восстановить исходные изображения). Смешиваем пирамиды по маске (которая тоже даунсэмплится до нужных разрешений) и восстанавливаем итоговое изображение с использованием смешанной пирамиды Лапласа, но для 2 самых ранних и низкочастотных уровней берем оригинальные куски пирамиды от target.
  5. Помимо этого после такого блендинга считают Global Contrast Factor (глобальная метрика, равная взвешенной сумме локальных контрастов, считаемых через L в Lab), и выход декодера умножают на отношение этого фактора в target и сгенерированном лице.


Результаты
В итоге получаются неплохие визуальные результаты в сравнении с DFL и подходом от Nirkin, основанном на 3dmm. В ablation авторы показывают положительное влияние progressive обучения на детализацию выхода сети, также показывают положительное влияние использования multi-band блендинга и последующего выравнивания контраста (в случае с выравниванием до блендинга получается хуже).


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


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




2. Beyond Accuracy: Behavioral Testing of NLP Models with CheckList


Авторы статьи: Marco Tulio Ribeiro, Tongshuang Wu, Carlos Guestrin, Sameer Singh (USA, 2020)
Оригинал статьи :: GitHub project :: (ACL 2020 best paper award)
Автор обзора: Юрий Кашницкий (в слэке yorko, на habr yorko)


Эта работа приоткрывает дверь во взрослое будущее, в котором будет недостаточно выкатить модельку и просто трекать набор метрик. Здесь речь про NLP, но основные тезисы переносятся в целом на весь ML в ближайшем будущем бизнес заставит нас отвечать за продукт и тестировать его поведение гораздо более системно.



Тут авторы переносят некоторые практики тестирования из SWE на NLP-модельки, в частности black-box testing (только вход-выход, вообще ничего не знаем про саму модель), minimum functionality test (когда на простых примерах проверяется основная функция модели), metamorphic test (небольшие пертурбации, не меняющие разметки, смотрим, как сильно меняется прогноз).


  • Выкладывают в open source тулзу CheckList, которая помогает автоматизировать и масштабировать создание простых тестов для NLP-моделей. Пример для sentiment analysis: по шаблону "I {negation} {pos_verb} the {thing}" можно наплодить много тест-кейсов с негативным сентиментом (eg. "I don't like the service"). Прикольно, что они используют RoBerta как MLM, чтоб подсказывать такие слова-вставки, например, для {pos_verb} это like, love, enjoy и т.д. если фантазии не хватает, то тут Роберта подскажет синонимов, причем по контексту.


  • На примере оценки тональности показывают, что и у коммерческих моделей от гигантов (Google, Amazon, Microsoft) и у SOTA академических моделей (BERT, RoBerta) очень много косяков (но это уже не черри-пикинг примеров, а именно тестирование, a disciplined approach). Интересно, что почти по всем тестам берты лучше коммерческих моделей (исключение устойчивость к нейтральным фразам, т.к. обучались на датасете SST с бинарными метками тональности).


  • Пообщались с командой Microsoft Text Analytics, за 5-часовую сессию успели научить их пользоваться тулзой CheckList, провести кучу тестов и найти множество багов в продакшн-системе, которая как-то тестируется внутри самого Microsoft и проходит итерации фидбека кучи пользователей. Если все именно так (а первый автор все же из Microsoft Research), то это просто эпический пример, как лидеров области за бесплатно консультируют и помогают найти кучу проблем в их продукте. Надеюсь, чуваки зарелизили не все, а половину функционала оставили для своего консалтинг-стартапа.



Скорее всего через несколько лет будут выработаны best practices тестирования ML моделей. Осталось самое интересное понять, как этим ML моделям все же не допускать "детских" ошибок. Систематическое тестирование напрямую с этим не помогает, зато позволяет подебажить модель и обнаружить косяки, неочевидные свойства и т.д., это уже немало.


Предлагают такой системный подход. Есть проверяемые качества (в статье Capabilities), их мы проверяем тестами разных типов. Здесь комментируется на примере анализа тональности, но в статье также анализируются поиск дубликатов (Quora Question Pairs) и Reading comprehension.


Предлагают проверять следующие качества (но можно и многие другие придумать):


  • словарь + POS насколько для задачи критичны определенные слова и их формы (например, добавление эмоциональных слов должно соответственно влиять на прогноз);


  • устойчивость (robustness) к небольшим изменениям, например, к опечаткам (или пример с тональностью: замена одного нейтрального слова на другое не должна особо менять прогноз);


  • NER понимание роли именованных сущностей (например, замена одной локации на другую не должна менять прогнозируемую тональность);


  • отрицание (negation) вот это вообще боль систем анализа тональности. Пример: "I thought the plane would be awful but it wasn't";


  • и некоторые другие: fairness, temporal, coreference, logic, тут уже от специфики задачи, у того же Reading comprehension будет больше проверяемых качеств.



Теперь 3 типа проверок:


  • minimum functionality test (навеяно юнит-тестами из разработки) примеры выше с шаблонами ("I {negation} {pos_verb} the {thing}") и отрицанием.


  • Invariance test небольшие изменения не должны влиять на прогноз (например, опечатки, добавление рандомных урлов и т.д.).


  • Directional Expectation test похоже на предыдущее, только ожидаем, что прогноз определенным образом изменится. Например, добавление "You are lame" должно сделать прогноз более негативным.



Некоторые интересные косяки моделей анализа тональности:


  • процент фэйлов близок к 100 у всех трех коммерческих моделей в тесте c отрицанием (I thought the plane would be awful, but it wasnt.);


  • коммерческие модели хорошо справляются с шаблонами "I am a {PROTECTED} {NOUN}", где {PROTECTED} из списка [black, atheist, gay, lesbian, ...]- правильно предсказывают нейтральную тональность для фраз типа "I am a lesbian woman". Дрючат их, гигантов, по fairness. BERT, наоборот, почти всегда говорит "negative" в таких случаях;


  • следует повторить удивительный факт, что почти по всем тестам фаинтюненные на SST модели BERT & RoBerta проявили себя лучше, чем коммерческие.



3. Thieves on Sesame Street! Model Extraction of BERT-based APIs


Авторы статьи: Kalpesh Krishna, Gaurav Singh Tomar, Ankur P. Parikh, Nicolas Papernot, Mohit Iyyer (UMass & Google Research, ICLR, 2019)
Оригинал статьи :: GitHub project :: Blog
Автор обзора: Юрий Кашницкий (в слэке yorko, на habr yorko)


TLDR
Забрасывая API с коммерческой BERT-based моделью запросами из почти случайных наборов слов (с лёгкими task-specific эвристиками), можно украсть модель, т.е. воссоздать почти такую же, как и модель-жертва. Рассматриваются способы защиты от такого хулиганства, но в этой борьбе брони и пушки впереди пока пушки.


Как это работает?
Хакер просто файнтюнит свою модель на ответах модели-жертвы (напоминает, кстати, sample-efficient knowledge distillation). И что, все настолько просто? Не совсем, далее идут эвристики. На совсем уж рандомных запросах не сработает, авторы это упоминают.




Для анализа тональности (SST2) эвристики простые слова берутся из топ-10к (по частотности) wikitext103, остальные заменяются на случайные из этого словаря топ-10к.


В MNLI (natural language inference), вход это пара предложений: посылка и заключение, предсказывается, как они связаны (entailment, contradiction, neutral). Посылка формируется так же, как для SST2, а заключение просто копирует посылку, и 3 слова заменяются на случайные из все того же словаря топ-10к wikitext103.


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


И так далее. Не rocket science вроде, но с такими эвристиками работает, а без них нет.


Идеи двух методов защиты.


Membership classification выявление выбросов, примеров не из распределения обучающей выборки. API вернет рандомный ответ для таких примеров. Для этого на бэкенде дополнительно строится классификатор real-fake, но и его можно надурить, т.к. классификатор не может предусмотреть произвольное распределение фейка.


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


Основные выводы:


  • рассмотрели 4 NLP задачи (sentiment analysis: SST2, natural language inference: MNLI, question answering: SQuAD 1.1. + BoolQ), в каждой из них удалось с помощью adversarial атаки обучить модель от 10% до 2% по метрикам хуже модели-жертвы;


  • цена такой атаки зависит от числа запросов и не превысила $400 в их экспериментах (для BoolQ всего $6);


  • атаки довольно эффективны и по числу примеров, т.е. хоть что-то осмысленное можно утащить даже с небольшим числом запросов (1к-10к), а с какого-то момента видно насыщение качества атакующей модели;


  • если выбирать запросы с высокой согласованностью прогнозов моделей жертв (например, если взять ансамбль моделей-жертв, обученных с разными сидами), то атака более эффективна;


  • аккуратно выбранные из Википедии параграфы улучшают атаку в сравнении рандомными запросами, но не сильно;


  • если в задаче классификации API выдает не распределение вероятностей, а только наиболее вероятный класс, атака все равно возможна, причём почти так же эффективна;


  • если взять атакующую модель пожирнее, то атака улучшается даже если архитектура не совпадает с архитектурой модели жертвы. e.g. если за API BERT-base, то атаковать лучше с BERT-large, чем BERT-base. И далее, если взять XLNet, то атака ещё лучше;


  • трансфер лернинг критичен (то что атакующие модели из BERT семейства уже видели много данных) обучиться на ответах модели-жертвы с нуля (без предобучения, т.е. с рандомных весов атакующей модели) вообще не получилось.



Еще одна статья, показывающая, как мало мы знаем про эти блэк-боксы, какая это пока leaky abstraction и как много ещё интересных новостей придет из мира adversarial атак и, шире, информационной безопасности в контексте ML.


4. Time-Aware User Embeddings as a Service


Авторы статьи: Martin Pavlovski et.al. (Yahoo! Research, Temple University, 2020)
Оригинал статьи
Автор обзора: Денис Воротынцев (в слэке tEarth, на habr tEarth)


Авторы исследуют вопрос создания эмбедингов активности юзера в сети для последующего использования в моделях второго уровня (ctr prediction, click-through rate). Предложенный подход лучше по качеству чем предложенные ранее. Авторы предлагают использовать полученные эмбединги в embeddings-as-service для своих внутренних (и возможно в будущем и для внешних) стейкхолдеров.


Предположим решается задача ctr predictions. На каждого пользователя есть информация об его активности в сети и время этой активности. Активность юзера имеет большое количество категорий: тысячи и десятки тысяч действий.


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


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


Авторы предложили следующую архитектуру и подход к обучению. Инпут sequence действий a1, a2, aL, aL+1 с временем этого действия t1, t2, tL, tL+1 (L длина sequence, aL+1 EOS токен).



Преобразование входного вектора активности это, как может оказаться, киллер-фича этой работы. Входной вектор активностей преобразуется в эмбединг активности aj -> vj (эмбединг слой, все стандартно). Затем считается stop feature текущее время / время последней активности в секвенсе j = tj / tL+1. Затем каждая активность мапится в latent space (j и j). j отображает влияние данной активности на секвенс эмбединг, а j и j влияние времени активности на секвенс эмбединг. Считаем temporal score j = (j + jj) (где сигмоида), на который потом будет домножен секвенс эмбединг v_hatj = j*vj. v_hatj подается в следующий слой.


Замечание от автора обзора: В настоящее время есть много подходов по добавлению информации о времени в эмбединг: конкат со временем, конкат с sin/cos времени, positional embeddings и т.п. Не очевидно использование латентных переменных, и преимущества считать именно так. Возможно, это объясняется непостоянностью t, то есть разница между tn, tn+1 очень сильно варьируется, но зачем тогда пихать сюда a_n еще раз.


Затем идет стандартный lstm слой, который кодирует инпут секвенс в эмбединг h (этот эмбединг и будет использоваться как целевой), из которого восстанавливается входной секвенс (стандартная seq2seq lstm модель). Затем идет full connected layer который считает вероятность каждой активности.


Авторы сравнили свой подход с предыдущими работами: fully-connected AE, seq2seq (lstm), time-aware seq2seq, ISA. Полученный подход лучше реконструирует активность (несколько метрик, два датасета).




Плюс авторы сравнили скоры подхода эмбединг + LR (Logistic Regression) на целевую задачу с моделями построенных на сырых данных для решения целевой задачи: LR, attention RNN (attRNN), xgboost. Авторы не могут сообщать скоры на своих датасетах, так что они привели прирост по сравнению с бейзлайном (LR на демографических фичах). Из таблицы 4 видно, что эмбединг + LR сравнялся по качеству с attRNN, обучение которого на порядок дольше.




Авторы в статье также рассказали про подход embedding as service.



Авторы статьи: Chenxi Liu, Piotr Dollr, Kaiming He, Ross Girshick, Alan Yuille, Saining Xie (Johns Hopkins University, Facebook AI Research, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Денис Воротынцев (в слэке tEarth, на habr tEarth)


Оказалось, что не особо.


Neural architecture search (NAS) позволяет найти оптимальную архитектуру для выбранной задачи. По сути, NAS это оптимизация гиперпараметров сети, где у нас есть изменяемые параметры (количество слоев, их тип, дропауты, количество нейронов в слое и т.п.) и метрика качества (здесь и далее accuracy); мы хотим найти такие параметры, чтобы качество -> max. NAS supervised метод обучения, нам нужны таргеты целевой задачи, чтобы найти оптимальную архитектуру.


К сожалению, это не всегда возможно. Например, в случае если для нашей задачи мало данных. Некоторые работы (Learning transferable architectures for scalable image recognition, CVPR) предлагают очевидный выход: давайте оптимизируем параметры на одном таске, а архитектуру применим на другом. Так, найдя сеть на cifar, можно применить ее к Imagenet.




Авторы данной работы решили пойти дальше: давайте вообще откажемся от использования лейблов целевой задачи и придумаем свои. По сути, нам все равно какие веса выучит сеть, нам важна архитектура. Авторы предлагают несколько тасок (прокси-задачи) для использования вместо лейблов: Rotation prediction (классификация, на какой угол повернули картинку), Colorization (pixel-wise classification: gray imgs -> colored imgs), Solving jigsaw puzzles (делим картинку на пазл, мешаем, сеть должна предикнуть как перемешали). Авторы прогнали 500 итераций NAS используя несколько методов поиска DARTS и NAS-Bench-101. Для каждой предложенной NAS архитектуры посчитали качество на прокси-задачу и качество на целевой задаче (переобучили архитектуру с таргетами целевой задачи), между этими метриками посчитали ранговую корреляцию. Оказалось, что корреляция довольно высокая (см. выше), топовые модели на прокси-задаче часто являются топовыми и на целевой задаче.


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


6. GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding


Авторы статьи: Dmitry Lepikhin, HyoukJoong Lee, Yuanzhong Xu, Dehao Chen, Orhan Firat, Yanping Huang, Maxim Krikun, Noam Shazeer, Zhifeng Chen (Google, 2020)
Оригинал статьи
Автор обзора: Артем Родичев (в слэке fuckai)


TL;DR


  1. Сделали модуль GShard, который позволяет скейлить нейросетевые модели с помощью нескольких простых функций репликации и шардирования тензоров по нескольким девайсам(TPU/GPU).
  2. С помощью GShard отскейлили трансформер на основе Mixture-of-Experts. Натренировали несколько моделей варьируя количество трансформер-слоев и экспертов. Тренировали на задаче multilingual machine translation на 100 языковых парах. Самая большая модель на 600B параметров, тренировали 4 дня на 2048TPU v3.
  3. Показали что их способ скейлинга трансформера является эффективным низкий communication cost между девайсами, а training cost растет сублинейно относительно роста размера модели.

Суть
Стало очевидно, что для получения SOTA нужно тренировать большие сети. Они лучше и быстрее сходятся, а также являются более sample efficient, чем аналогичные сети меньшего размера. Однако нет удобных инструментов для скейлинга сетей. Из коробки model parallelism в pytorch или tf работает неэффективно раздувает вычислительный граф, ведет к большим накладным расходам на коммуникацию между девайсами, добавляет sequential dependency в вычислениях. Если же хочется сделать эффективный скейлинг своей модели, то нужно заниматься инженерией и ручным раскладыванием вычислительного графа по девайсам. Все это плохо, хочется тренировать большие сети удобно и эффективно.


Для этого гугл предложили фреймворк GShard, который включает в себя:


  1. Легковесное API c 3 основными командами:


    • replicate(tensor) реплицировать (копировать) веса на все девайсы (TPU/GPU);
    • split(tensor, split_dimension, num_partitions) делит тензор на num_partitions по заданной размерности split_dimension и раскладывает каждую партицию на соответствующий девайс;
    • shard(tensor, device_assignment) обобщение split(), на какие девайсы нужно шардировать тензор целиком.

  2. Компилятор вычислительного графа, который оптимально строит единый для всех девайсов вычислительный граф и рассылает его на все девайсы. Компилятор реализует эффективное шардирование и реплицирование весов по девайсам. Работает в парадигме SPMD (Single Program Multiple Data), что делает время компиляции вычислительного графа константным, независимым от количества девайсов.



На основе GShard сделали огромный трансформер, который назвали Sparsely-Gated Mixture-of-Experts Transformer. Представляет из себя слегка модифицированный оригинальный трансформер. Обычный трансформер блок (слой) состоит из бутерброда [вход -> мультихэд-аттеншн -> нормализация -> FNN -> нормализация -> выход] + два res коннекшена (см картинку). Финальный трансформер состоит их N таких слоев. Для скейлинга предлагается в каждом нечетном слое добавить Mixture-of-Experts вместо FNN. Mixture-of-Experts представляет из себя E полносвязных двухслойных FNN сетей + gating механизм, который решает, какому подмножеству экспертов мы передадим на вычисление текущий токен. Аутпут с этого блока считается как усреднение выходов всех FNN, которые участвовали в вычислении для данного входа, умноженные на соответствующие гейтинг веса.




Gating механизм реализуется софтмаксом над количеством экспертов, где i-ый аутпут означает важность/вес i-го эксперта. Хочется, чтобы гейтинг эффективно и равномерно балансировал нагрузку между экспертами и соответственно девайсами. Для этого применим следующие хаки:


  • Чтобы не перегружать экспертов, ограничим capacity каждого эксперта как O(N/E), где N кол-во токенов в батче, E кол-во экспертов. Введем каунтер, сколько токенов мы обработали данным экспертом, и если превысили его capacity, то не делаем вычисления этим экспертом для очередного токена.
  • Добавляем к NLL лоссу дополнительный Auxiliary loss минимизирующий долю токенов на эксперта. Это форсит гейтинг функцию не выбирать каждый раз одних и тех же экспертов, а балансировать между всеми.
  • Для каждого токена ограничим вычисления максимум двумя экспертами, которые получили максимальные веса после софтмакса в гейтинг функции. При этом второй эксперт может иметь маленький вес и тогда мы сделаем вычисление, результаты которого почти не повлияют на аутпут. Поэтому будем делать вычисление на втором эксперте с вероятностью пропорциональной его весу.

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


Результаты
Для демонстрации подхода выбрали задачу multilingual machine translation на 100 языковых парах, при этом рассматривали перевод только в одну сторону, НА английский. Языковые пары есть как low-resource на десятки тысяч примеров, так и high-resource на миллиарды сэмплов. Итоговый трейнсет составил 13B сэмлов.


При обучении сетей на задачу multilingual перевода наблюдается два свойства:


  1. Low-resource языковые пары бенефитят из-за positive transfer. Качество на таких языковых парах улучшается из-за шаринга параметров сети при обучении с другими high-resource языками.
  2. High-resource языковые пары наоборот деградируют из-за capacity bottleneck. Качество на таких языковых парах ухудшается из-за подмешивания многих других языков. Модели перестает хватать capacity, чтобы хорошо решать задачу перевода для всех языков одновременно.

Первое свойство нам на руку, а второе MoE Transformer исправляет тем, что имеет большое количество параметров и capacity.


Выучили 6 разных моделей, варьируя количество слоев(12 или 36) и кол-во экспертов(128, 512, 2048). Самая большая модель на 36 слоев и 2048 имеет 600B параметров. Интересно, что все модели тренировали в fp32 для стабильности трейна. Пробовали выучить модель на 1T параметров c bfloat16, но она не заработала из-за численной нестабильности. Каждую модель учили показав одинаковое количество токенов. Всего токенов 1T (10^12).


В качестве первого бейзлайна взяли 100 моделей, каждая по 400М параметров, и каждая училась на своей отдельной языковой паре. Второй бейзлайн 96 слойный обычный трансформер без MoE на 2.3B параметров, его учили одновременно на всех языковых парах, причем учили 40 дней на 2048 TPU (235 TPU лет).


По графикам качества видно, что увеличение глубины модели всегда ведет к значимому увеличению качества как для low-resource, так и для high-resource языковых пар. Также видно, что увеличение количество экспертов при одинаковом количестве слоев тоже бустит качество, особенно для high-resource языках из-за расслабления capacity bottleneck.


Еще показали, что глубокие модели сходятся намного быстрее и являются более sample efficient, чем неглубокие. При этом увеличение количества экспертов при одинаковой глубине не всегда приводит к лучшей сходимости (модель с 512 экспертами сошлась быстрее/также как и модель с 2048 экспертами)




7. Data Shapley: Equitable Valuation of Data for Machine Learning


Авторы статьи: Amirata Ghorbani, James Zou (USA, 2019)
Оригинал статьи :: GitHub project
Автор обзора: Денис Воротынцев (в слэке tEarth, на habr tEarth)


SHAP как алгоритм поиска важных глобальных и локальных фичей это, пожалуй, сота современного интерпретируемого мл. Подход основан на расчете Shapley values, идея взята из теории игр. Каждая фича принимается как игрок в коалиции, цель которой максимизация скора. Shapley value фичи при интерпретации одного примера это вклад данной фичи в финальный предикт по сравнению со средним предиктом. Глобальная важность фичи это сумма абсолютных значений shapley values каждого примера в данном датасете. Преимущества данного подхода универсальность, мы можем считать shapley values для любой модели. Недостаток необходимость большого количества вычислений.


Авторы задались вопросом: что если мы применим shapley values для поиска наиболее важных примеров в обучающей выборке? Известно, что в датасете может быть шум в разметке, некоторые примеры могут просто ухудшать скор и так далее. Идея в том, что мы найдем вклад каждого примера в финальный скор и удалим те примеры, которые ухудшают скор.


Поскольку для точного расчета вклада каждого примера необходимо рассмотреть n! комбинаций (n количество сэмплов в обучающей выборке, рассмотреть обучить модель и рассчитать скор), авторы предложили использовать Монте-Карло перемешивание для аппроксимации расчетов (TMC-Shapley algorithm):


  1. Случайно перемешиваем индексы обучающей выборки idx.
  2. Проходим по индексам j = 1 до idx: создаем обучающую выборку (сэмплы от 1 до текущего индекса j), обучаем модель на сэмле, считаем лосс. Вклад j примера = текущий лосс минус лосс на прошлой итерации.
  3. Повторяем пункты 1-2 до сходимости (критерий приращение shapley values меньше константы), итоговый shapley value примера среднее по всем итерациям.

Авторы также предложили G-Shapley algorithm, который может применяться при обучении сетей. Отличие по сравнению с TMC-Shapley algorithm состоит в том, что мы не обучаем модель с нуля, а используем bs=1 и смотрим на историю лосса.


Подход был протестирован на двух датасетах: "In this experiment, we use the UK Biobank data set (Sudlow et al., 2015); the task is predicting whether an individual will be diagnosed with Malignant neoplasm of breast and skin (ICD10 codes C50 and C44, binary classification) using 285 features. Balanced binary data sets for each task are created and we use 1000 individuals for the task of training. Logistic regression yields a test accuracy of 68.7% and 56.4% for breast and skin cancer prediction, respectively. Performance is computed as the accuracy of trained model on 1000 separate patients."


На двух датасетах алгоритм сошелся за 2к итераций, что конечно быстрее чем 1000! итераций (в трейне было 1k примеров), но далеко до идеала: "For all the experiments, calculating data Shapley values took less than 24 hours on four machines running in parallel (each with 4 cpus) except for one of the experiments where the model is a Conv-Net for which 4 GPUs were utilized in parallel for 120 hours."




Подход сравнивают с leave-one-out подходом. Предложенный подход значительно обходит loo, но требует в 2к раз больше времени на расчет. Авторы также рассмотрели задачу поиска шума в разметке, где продемонстрировали значительные приросты по сравнению с loo. Впрочем, loo это не сота этой задачи.


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


8. Language-agnostic BERT Sentence Embedding


Авторы статьи: Fangxiaoyu Feng, Yinfei Yang, Daniel Cer, Naveen Arivazhagan, Wei Wang (Google AI, 2020)
Оригинал статьи :: GitHub project :: Blog
Автор обзора: Андрей Лукьяненко (в слэке artgor, на habr artgor)


Очередная SOTA статья от Google. Они адаптировали мультиязычный BERT для создания эмбеддингов предложений независимых от языка для 109 languages (в том числе для русского)! SOTA на Tatoeba, BUCC и UN.


Общий подход
Обычно MLM (masked language mode) не дают хороших эмбеддингов для предложений их приходится тюнить для конкретной задачи. А мультиязычные модели с эмбеддингами предложений часто не делают MLM претрейн.


Так что авторы решили получить мультиязычные эмбеддинги предложений, собрав кучу идей: MLM + TLM (translation language model).


Если говорить про технические детали, то используют dual-encoder с additive margin softmax loss. Два предложения кодируются по отдельности, но у энкодера пошаренные веса. В качестве эмбеддига предложений берут токен с последнего слоя. Схожесть между предложениями считают по косинусной схожести. В итоге SOTA, особенно на языках с небольшим количеством данных.


Данные
Тексты на одном языке взяли с CommonCrawl и Wikipedia. 17B предложений. Двуязычные пары предложений напарсили с использованием bitext mining system. И потом фильтровали активно. Получили 6B пар предложений.


Модель: Bidirectional Dual Encoder with Additive Margin Softmax.




Тренировка моделей


  • Transformer с 12 слоями, 12 головами и 768 hidden size.
  • Тренировали на 32-core slices Cloud TPU V3 pods.
  • Батч 2048, максимальная длина последовательности 64.
  • Margin value 0.3.
  • Модель тренируется 50k шагов (меньше одной эпохи).
  • Использовали AdamW, lr 1e-5, weight decay.
  • Во время тренировки нормализованные эмбеддинги предложений домножаются на 10. Это типа важно.
  • Параметры тюнили на holdout.

Результаты


SOTA на Tatoeba, BUCC и UN.




Анализ


  • Additive margin очень важная штука. При нулевом значении качество модели низкое (60+ или 70+ P@1 на UN). При значении 0.1 качество уже 80+. А более высокие значения работают лучше на разных датасетах.
  • Претренировка очень важна (см таблицу ниже).
  • По сравнению с Multilingual BERT LaBERT работает намного лучше на языках, в которых меньше данных. Возможные причины: в разы увеличили словарь (500k vs 30k), TLM претренировка и то, что претренировали не только на вики, но и на commoncrawl.
  • Важность выбора данных. Оказывается, что если просто напарсить данные из интернета, то модель будет хреновая. А вот если их отфильтровать и улучшить, то качество модели улучшится



Мнение автора обзора: "В общем в целом с одной стороны очень круто, с другой взяли побольше данных, улучшили их качество и объединили известные подходы к тренировке моделей. Впрочем. Cross-Accelerator Negative Sampling выглядит весьма круто"


9. Self-Supervised Learning for Large-Scale Unsupervised Image Clustering


Авторы статьи: Evgenii Zheltonozhskii, Chaim Baskin, Alex M. Bronstein, Avi Mendelson (Technion, Israel, 2020)
Оригинал статьи :: GitHub project
Автор обзора: Евгений Желтоножский (в слэке evgeniyzh, на habr Randl)


Обзор от автора статьи.


Ниже следует рассказ о работе, и, заодно, проведен краткий обзор self-supervised learning (речь о vision, в NLP с BERT это отдельная история). Как оказалось, self-supervised learning это отличный бейзлайн для fully unsupervised clustering того же ImageNet (39% accuracy с 1000 кластеров и 46% с 1500).


Self-supervised learning
Сам по себе self-supervised learning в последнее время очень популярен, в первую очередь у больших компаний, которым собрать данные гораздо проще чем их разметить. В середине 2019 был дан довольно мощный буст результатам за счет ресерча именно из гугла и фейсбука. Особенно успешны сейчас подходы на основе contrastive losses. За подробностями предлагаю обратиться к неплохим обзорам 1 и 2, которые к сожалению устаревают неимоверно быстро.


Вкратце, существующие методы приведены в таблице ниже. Остановлюсь на подходах к измерению перформанса. Основных подхода два, с вариациями: либо обучить линейный классификатор на фичах которые извлекает сеть, либо файн-тюнить сеть (тут обычно берется либо 1-10% ImageNet, либо COCO и друзья). Проблема с первым подходом в том что хорошие фичи не обязательно линейно разделимы, а со вторым, что многое зависит от того как файнтюнить (см. SimCLR v2). Я давно задавался вопросом, почему никто не пытается сделать fully unsupervised эвалюацию таких методов. После выхода статьи которая получила неплохие результаты на ImageNet, я понял что настало время написать код и проверить результаты. Так как большинство self-supervised методов выкладывают и код, и модели, получилось сделать довольно обширный обзор не потратив over 9000 gpu-часов.




Для начала, метрики. Не буду задерживаться на них, но unsupervised learning оценивать сложнее. К счастью, у нас есть лейблы поэтому мы можем посчитать accuracy. Кроме этого, мы считаем пару метрик основанных на попарной точности (для каждой пары примеров positive, если они в одном кластере, и negative иначе). Кроме этого мы добавляем поправку на рандом, и получаем две основные метрики: adjusted Rand Index (ARI) и adjusted mutual information (AMI). Добавили также mutual information (MI) без поправки, потому что использовался предшественниками.


Предложенный подход
Сам подход, представленный в статье, максимально прост (напоминаю, цель получить бейзлайн и сравнить методы): достаем фичи из трейнинга и валидации, прогоняем через PCA, тренируем на этом k-means. Для подсчета точности считаем linear assignment. Этого оказалось достаточно чтобы получить около-sota. Заодно сравнили с топовыми supervised сетками. Результаты довольно неплохо коррелируют с точностью линейного классификатора (наверное это логично). Интересное исключение большие эмбеддинги работали плохо. Возможно это недостаток k-means, но может и нет.




Кроме ImageNet протестировали на ObjectNet. Оказалось, что после тренировки на ImageNet ничего дельного на нем не выходит, даже если использовать лейблы с валидации для назначения классов (исключение BigBiGAN). У supervised те же проблемы.


Зато если тренировать k-means на самом ObjectNet, то какой-никакой сигнал есть (6.5% accuracy). Что интересно, для классов которые присутствуют в ImageNet и для тех, которые отсутствуют, точность практически одинаковая.


Наконец, сделали небольшой ablation study. Проверили как влияет количество измерений инпута (после PCA) и количество кластеров (до 2000 дает неплохой буст даже label-independent метрикам).




По результатам статьи возникает немало вопросов, на которые быстро ответить не удалось. Авторы надеются впоследствии заняться ими более плотно, но там уже без миллиона GPU обойтись будет сложно.


10. Batch-Channel Normalization and Weight Standardization (2 papers)


Авторы обоих статей: Siyuan Qiao, Huiyu Wang, Chenxi Liu, Wei Shen, Alan Yuille ( Johns HopkinsUniversity, USA, 2019)
Автор обзора: Эмиль Закиров (в слэке bonlime)
Статья 1: Micro-Batch Training with Batch-Channel Normalization and Weight Standardization
Оригинал статьи 1 :: GitHub project
Статья 2: Rethinking Normalization and Elimination Singularity in Neural Networks
Оригинал статьи 2


Ранее был обзор на способы нормализации в сетках (Group Norm и Weight Standardization). Авторы статьи про Weight Standardization выпустили update на свою статью, который такой большой, что больше похож на новую и достоин отдельного обзора. Отдельно стоит отметить, что статья очень хорошо написана, включает много экспериментов на разных датасетах и в разных доменах (Imagenet / COCO / PASCAL VOC / Something-SomethingV1)


TLDR
Авторы пытаются ответить на следующие вопросы:


  • Почему Group Norm (GN) работает хуже Batch Norm (BN) и как это можно исправить?
  • Почему Weight Standardization (WS) помогает?

Предлагают новый Batch-Channel Normalization (BCN), который работает лучше, чем BN и GN, и при этом его можно обучать в micro-batch режиме с 1 img/gpu.


Batch-Channel Normalization = GroupNorm(BatchNorm(x)), только BN использует накопленные running mean/var статистики для нормализации, а не статистики батча, тем самым делая возможность обучаться в micro-batch режиме.




Утверждается, что одна из вещей которые сильно усложняет оптимизацию сеток наличие мертвых нейронов или слоёв, которые никогда не активируются. Они называют эту проблему singularity и ищут как с ней бороться. В случае с BN, когда каждый канал нормализуется отдельно, всегда есть гарантия, что после ReLU какая-то часть нейронов будет не нулевой. В случае же Group Norm, если у каналов в группе очень разные статистики, некоторые каналы могут активироваться меньше других или не активироваться вообще, что усложняет оптимизацию и влияет на финальный перфоманс (Fig. 7).


Практические эксперименты на cifar показали, что разброс в статистиках между каналами (измеренный в так называемом statdiff) и правда существенный. (Fig.6). Чтобы избежать разброса в статистиках между каналами, можно каждый канал отдельно нормализовать (с помощью модифицированного BN) и только затем применить Group Norm. Не лишняя ли вторая нормализация? Авторы утверждают что нет, потому что 1) BCN позволяет учиться в micro-batch режиме 2) GN нормализует каждый пример отдельно и поэтому вносит больше нелинейности 3) GN не зависит от статистик и поэтому более устойчив на новых данных.


Как Weight Standardization (WS) решает проблему с singularity? С помощью математики можно показать, что с WS статистики выходных каналов становятся похожи на статистики входных, таким образом, если нормализовать входную картинку, то и дальше все каналы будут иметь примерно одинаковые распределения => stat diff будет меньше => дальше от singularity => оптимизировать будет проще и перфоманс будет выше. Последняя => не очень очевидная, авторы доказывают её с помощью экспериментов (см. картинку ниже).




Результаты на Imagenet:



Мнение автора обзора:


  1. GN + WS стабильно докидывал в моих экспериментах при BS=4, но на больших BS работало хуже чем BN + WS.
  2. Не пробовал применять WS для efficientnet, потому что там не очень понятно, как нормализовывать по группам и в статье Understanding the Disharmony between Weight Normalization Family and Weight Decay (пункт 6.7) писали, что оно плохо работает.
  3. В торче 1.6 наконец замерджили PR на ускорение GN, так что теперь оно работает почти так же быстро как BN, что очень радует.
Подробнее..

Шесть степеней свободы 3D object detection и не только

28.10.2020 20:04:59 | Автор: admin

В компьютерном зрении часто приходится работать с двумерными изображениями, и значительно реже - с 3D объектами. Из-за этого многие ML инженеры чувствуют себя неуверенно в этой области: много незнакомых слов, непонятно, куда тут применить старых друзей Resnet и Unet. Поэтому сегодня я хотел бы немного поговорить о 3D на примере задачи определения шести степеней свободы, что в каком-то виде синонимично 3D object detection. Я разберу одну из относительно свежих работ на эту тему с некоторыми отступлениями.

Меня зовут Арсений, я работаю ML инженером и веду Telegram-канал partially unsupervised. Эта статья написана по мотивам моего же видео для Data Fest 2020, секция CV в индустрии.

Кратко о задаче

Для начала давайте определимся, что такое шесть степеней свободы (6 DoF - degrees of freedom). Представим себе некоторый ригидный (неизменяемый, т.е. при трансформации все точки будут оставаться на той же дистанции друг от друга) объект в трехмерном мире. Чтобы описать его положение относительно наблюдателя понадобится 6 измерений: три будут отвечать за повороты по разным осям, а еще три - за смещение по соответствующим осям. Соответственно, имея эти шесть чисел, мы представляем, как объект расположен относительно какого-то базиса (например, точки, с которой ведется фотосъемка). Эта задача является классической для робототехники (где находится объект, который нужно схватить роборукой?), дополненной реальности (где нарисовать маску в MSQRD, ушки в Snapchat или кроссовки в Wanna Kicks?) , беспилотных автомобилей и других доменов.

Будем рассматривать статью MobilePose: Real-Time Pose Estimation for Unseen Objects with Weak Shape Supervision (Hou et al., 2020). Эта статья, написанная авторами из Google Research, предлагает надежный и, что немаловажно, быстрый пайплайн для решения задачи, будет уместно разобрать его по частям.

Пайплайн состоит из трех основных кусков:

  1. Backbone достаточно классический, архитектура в виде песочных часов должна быть знакома каждому, кто хоть раз обучал Unet.

  2. Выходы сети не выглядят инновационно. Detection, regression - все знакомые слова! Впрочем, насчет shape могут возникнуть вопросы. Но давайте отложим их на время.

  3. Постпроцессинг может показаться загадочным для тех, кто не в теме. Что такое EPnP и почему оно превращает 2D точки в 3D bounding box?

3D для чайников

И здесь сразу нужно сделать важное отступление, которое поможет нам ответить на все эти вопросы. Давайте высокоуровнево посмотрим на некоторую математику 3D мира. Пусть есть некоторый набор 3D-точек X - матрица размером (n, 3), в которой n - количество точек. Как мы помним, шесть степеней свободы - это три поворота и три смещения, т.е. Rigid transformation. Если обозначить R матрицу поворота, а t - вектор переноса (rotation и translation соответственно), будет соблюдаться такое уравнение:

X = X @ R + t

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

Но X - это все еще 3D-координаты. Потому стоит сказать, что еще существует некоторая проективная матрица P. Эта матрица характеризует то, как мы проецируем объект на двумерную плоскость, условно рендерим его. Эта матрица зависит от размера фотографии, фокусного расстояния, искажений, но в нашей задаче ее можно считать константной. Имя такую матрицу, можно получить 2D координаты точек, просто умножив ее на X:

x = X @ P

Совсем на пальцах: мы ищем, как нужно повернуть и подвинуть некий объект, чтобы какие-то его точки спроецировались так, как они сейчас изображены на фотографии. Я все упростил до неприличия, потому отправляю всех желающих просветлиться посмотреть на CS231a.

Подзадача нахождения R и t, зная X, x и P, называется Perspective-n-Point. Т.е. мы знаем, как выглядит наш объект в 3D (это X), знаем, на какое изображение он спроецирован (P) и где на этом изображении находятся его точки. Выглядит как задача оптимизации! Есть целое семейство алгоритмов, которые решают эту задачу, например, некоторые уже реализованы в OpenCV.

Еще некоторые ссылки по теме:
Monocular Model-Based 3D Tracking of Rigid Objects: A Survey (Lepetit et. al 2005) - классический обзор;
EPnP: An Accurate O(n) Solution to the PnP Problem (Lepetit et. al 2008) - сильный бейзлайн;
PnP-Net: A hybrid Perspective-n-Point Network (Sheffer and Wiesel, 2020) - для тех, кто хочет скрестить ужа и ежа, т.е. добавить к PnP немного диплернинга.

Кстати, к этой проблеме подходят и с другой стороны. Адепты deep learning могут найти множество статей, где используется специальный projection layer, который преобразует 2D и 3D точки друг в друга. Обычно, чтобы обучить такой слой, используют синтетические данные, т.к. 3D координаты из реального мира получать дорого и сложно. Пример такой статьи.

Где взять 3D точки?

Итак, нам нужен X - напомню, это набор 3D точек. Откуда его взять?

Самый простой вариант - пытаться найти один и тот же объект на всех изображениях. Берем какую-то 3D CAD модель (готовую, рисуем с нуля, сканируем настоящий объект специальным сканером) и используем его (точнее, какие-то его точки) в качестве X. Иными словами, делаем явное допущение "на фотографии находится именно такой объект" - на первый взгляд, это прямо-таки нагло, но практика показывает, что для оценки 6 DoF этого достаточно.

Более сложный подход - так называемые параметризированные модели. Образцовый пример - Basel Face. Исследователи из Университета Базеля отсканировали много лиц и при помощи PCA обучили такую модель, чтобы изменение малого числа ее параметров позволяло сгенерировать эти 3D лица. Таким образом, можно крутить малое количество ручек - главных компонент и получать довольно разные модели.

Параметризованная модель может быть и куда проще. Например, если мы ищем на фотографии 3D bounding box, в качестве базовой модели можно использовать куб, а для параметризации использовать его соотношения длины-ширины-высоты.

Если наша 3D модель параметризована, ее параметры можно подбирать разными итеративными методами и выбирать такую, на которой reprojection error будет меньше. Т.е. берем некоторую модель X, решаем PnP, получаем R и t и выбираем такой X, чтобы разность x и (X @ R + t) @ P была минимальна, для примера можно посмотреть на procrustes analysis.

Истинные диплернеры идут дальше и в каком-то виде выучивают или 3D модель, или ее параметры. Хороший пример - известная работа DensePose от Facebook Research, которая популяризовала подход с выучиванием dense карты координат. Т.е. модель предсказывает для каждого пикселя его относительное расположение на 3D модели. Дальше можно найти соответствия и получить для каждого пикселя некоторое приближение его 3D координаты.

В статье, которую мы изначально взялись разбирать, есть выход с таинственным названием shape. В зависимости от наличия grouth truth данных (об этом немного позже) авторы либо учат там сегментационную маску объекта (т.н. weak supervision, для улучшения сходимости), либо как раз карту координат объекта.

Также может возникнуть вопрос - координаты каких именно точек мы хотим найти? Ответ простой: на самом деле, нам все равно. 3D модель обычно состоит из тысяч вершин, мы можем выбрать подмножество по своему вкусу. Единственный более или менее важный критерий - приблизительная равноудаленность точек друг от друга; в случае неудачной выборки решение PnP становится нестабильным.

Где взять 2D точки?

Итак, с 3D объектом худо-бедно разобрались, давайте пойдем в более знакомую большинству CV инженеров область, т.е. вернемся в 2D и подумаем, где взять координаты на плоскости.

Для получения 2D координат точек (обычно эта задача называется keypoint detection) популярны два основных подхода: регрессия напрямую (последний слой сети выдает x, y для каждой точки) и heatmap-регрессия (последний слой выдает тепловую карту с пятном около точки). Первый подход может быть быстрее, т.к. необязательно выстраивать полную encoder-decoder архитектуру, второй обычно точнее и достаточно легко обучается (это почти та же сегментация).

изображение взято из Adaptive Wing Loss for Robust Face Alignment via Heatmap Regressionизображение взято из Adaptive Wing Loss for Robust Face Alignment via Heatmap Regression

Авторы MobilePose не пошли ни по одному из этих путей и придумали интересный гибрид, вдохновившись современными безанкорными архитектурами для детекции вроде CenterNet. Помните, на схеме есть головы Detection и Regression? Так вот, Detection голова предсказывает центр объекта, а Regression - где вершины объекта находятся относительно этого центра.

В этом подходе есть изящный трюк. Я много писал о том, как выбрать 3D модель, а в этом случае все осознанно упрощается: в качестве модели используется простой параллелепипед, он же 3D bounding box! То есть X - это вершины бокса, а x - проекция этих вершин. Значит, достаточно знать соотношения сторон этого бокса (которые мы получаем из самой архитектуры детектора), и остальная магия ни к чему.

Особенности приготовления данных

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

Unlike 2D object detection, it is prohibitive to manually label data for 3D detection. Due to this difficulty of collecting sufficiently large amounts of labeled training data, such approaches are typically trained on real data that are highly correlated with the test data (e.g., same camera, same object instances, similar lighting conditions). As a result, one challenge of existing approaches is generalizing to test data that are significantly different from the training set.

Synthetic data is a promising alternative for training such deep neural networks, capable of generating an almost unlimited amount of pre-labeled training data with little effort. Synthetic data comes with its own problems, however. Chief among these is the reality gap, that is, the fact that networks trained on synthetic data usually do not perform well on real data.

В рассматриваемой статье авторы сделали один из таких трюков: вместо того, чтобы бездумно рендерить весь мир, они сделали комбинацию реальных и синтетических данных. Для этого они взяли видео из AR-приложений (хорошо быть гуглом и иметь много данных из ARCore). В таких видео есть и знание о плоскостях, оценка 6 DoF, полученная при помощи визуальной одометрии, и оценка освещения. Это позволяет рендерить искусственные объекты не где попало, а только на плоских поверхностях, адаптируя освещенность, что значительно снижает reality gap между синтетическими и реальными данными. К сожалению, повторить этот трюк в домашних условиях кажется довольно сложным.

Все вместе

(Сделано из палок и скотча за полчаса)(Сделано из палок и скотча за полчаса)

Ура, мы галопом пробежались по всем ключевым концепциям пайплайна! Этого должно хватить, чтобы читатель смог собрать из open source компонентов, например, приложение, которое будет рисовать маску на лице (для этого можно даже не учить модели самостоятельно, готовых сетей для face alignment немало).

Конечно, это будет только прототип. При доведении такого приложения до продакшена возникнет еще много вопросов, например:

  • Как добиться консистентности между кадрами?

  • Что делать с неригидными объектами?

  • Что делать, если объект частично не виден?

  • Что делать, если в кадре много объектов?

Именно там начнутся настоящие приключения.

Подробнее..

Data Fest 2020 полностью в Online уже завтра

18.09.2020 14:13:41 | Автор: admin
Data Fest пройдет в этом году в онлайн формате 19 и 20 сентября 2020. Фестиваль организован сообществом Open Data Science и как обычно соберет исследователей, инженеров и разработчиков в области анализа данных, искусственного интеллекта и машинного обучения.

Регистрация. Ну а дальше к деталям.



События этого года влияют не только на людей и экономику, но и на организацию мероприятий. Поэтому Data Fest в этот раз превращается в 2х дневный глобальный бесплатный фест, проходящий в формате онлайн-конференции. Присоединиться однозначно стоит, у вас будет уникальная возможность пообщаться с командами Мегафона, McKinsey, Huawei, Yandex, с топовыми организаторами из ODS.ai и другими специалистами в области технологий со всего мира, не вставая с дивана.

В 2019 году мы собирались на площадках в таких городах как: Минск, Одесса, Новосибирск и даже, на минуточку, в Дубае. За прошлый год мы разослали тысячи инвайтов на наши мероприятия, но вот Data Fest 2020 впервые соберет нас в онлайн.

Программа и треки


Data Fest 2020 глобальное онлайн мероприятие, состоящее из 5 тематических блоков. Для участников будут доступны десятки выступлений, некоторые из которых будут проходить параллельно. Дополнительно более трети всего контента феста будет доступно на английском языке. Так что встретимся в эти выходные, чтобы обсудить горячие темы:

  • Бизнеса важные темы со стороны бизнеса.
  • Индустрии применение DS/ML в индустрии.
  • Инженерии технические секции о прикладных методах и о том, как это работает.
  • Науки научные секции по актуальным и горячим темам.
  • Сообщества жизнь сообщества и специалистов.

P.s. Все доклады по темам сформированы в треки, которые в свою очередь состоят из видео-докладов, практических заданий и статей. Важно, что все треки навсегда попадут в историю ODS.ai, сформировав базу знаний для следующих поколений дата-саентистов.

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



Основные активности


Несмотря на новый формат проведения феста, мы постарались сохранить основные цели и ценности мероприятия. Нетворкинг и возможность послушать доклады DS комьюнити мы оставляем и переносим в онлайн режим:

  • Livestream конференция на youtube: спикеры секций, беседы с Алексеем Натекиным, основателем ODS.ai, включения из разных городов, разбавленные умиротворяющими лесными пейзажами (с ламами и оленями (и это не шутка));
  • Networking в Spatial Chat: максимально приближенный к офлайн конференции формат. В комнате можно вести несколько бесед параллельно, присоединяясь к той, которая наиболее интересна (или куда возьмут).

Вроде все по-старому. А теперь разберемся с доступом.
Смотреть прямую трансляцию феста может любой желающий, достаточно просто подключиться 19 и 20 сентября к эфиру по ссылке, которая будет доступна на сайте. А вот чтобы попасть в networking комнаты, нужна регистрация (да-да, она обязательна). Комнаты будут сгруппированы по существующим трекам, их порядка 35.



Ну а если вы еще сомневаетесь, нужно ли участвовать в Data Fest 2020, то вот вам пара весомых причин:


  • Оценить новый формат: пожалуй, такого масштабного онлайн ивента в области Data Science еще не было.
  • Послушать спикеров: среди них заявлены Алексей Натёкин основатель сообщества ODS.ai, организатор Data Fest, Валерий Бабушкин руководитель управления развития данных в компании X5 Retail Group, Михаил Рожков основатель онлайн-курсов по управлению экспериментами и проектированию машинного обучения, Асхат Уразбаев управляющий партнер в ScrumTrek, Павел Плесков digital nomad, data scientist в стартапе Praxis Pioneering, Eghbal Rahimikia доктор философии Alliance Manchester Business School, University of Manchester, Ser-Huang Poon профессор University of Manchester, Alliance Manchester Business School и это далеко не все.
  • Узнать новое по темам ML, Big Data, Quantum Computing, Computer Vision, Индустрия Антифрода/Антиспама, математическую оптимизацию задач ML, ML Repa, и многого другого. Полный список треков на сайте.
  • Пообщаться с DS командами Мегафона, McKinsey, Huawei, Yandex
  • Нетворкать, прокачивать soft skills и послушать, как строится карьера в Data Science.



Но что остается неизменно Data Fest, это по-прежнему глобальный мировой ивент. И это не просто слова. Присоединяйтесь!

Подробнее..

Итоговые проекты курса Deep Learning in Natural Language Processing (by DeepPavlov Lab)

07.08.2020 14:13:35 | Автор: admin
Недавно завершился Deep Learning in Natural Language Processing, открытый образовательный курс по обработке естественного языка. По традиции кураторы курса сотрудники проекта DeepPavlov, открытой библиотеки для разговорного искусственного интеллекта, которую разрабатывают в лаборатории нейронных систем и глубокого обучения МФТИ. Курс проводился при информационной поддержке сообщества Open Data Science. Если нужно больше деталей по формату курса, то вам сюда. Один из ключевых элементов DL in NLP это возможность почувствовать себя исследователем и реализовать собственный проект.

Периодически мы рассказываем на Medium о проектах, которые участники создают в рамках наших образовательных программ, например о том, как построить разговорного оракула. Сегодня мы готовы поделиться итогами весеннего семестрового курса 2020 года.



Немного данных и аналитики


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

Вернемся к участникам. Неужели все окончили курс? Ответ, конечно, очевиден. С каждым новым заданием желающих становилось все меньше и меньше. Как итог то ли из-за карантина, то ли по другим причинам, но к середине курса осталась только половина. Ну что ж, а дальше пришлось определяться с проектами. В качестве итоговых участниками было заявлено семьдесят работ. А самый популярный проект Tweet sentiment extraction девятнадцать команд пытались выполнить задание на Kaggle.

Подробнее про представленные проекты


На прошлой неделе мы провели заключительное занятие курса, где несколько команд представили свои проекты. Если вы пропустили открытый семинар, то мы подготовили запись. А ниже мы постараемся кратко описать реализованные кейсы.

Kaggle Jigsaw: Multilingual Toxic Comment Classification


Роман Щекин (QtRoS), Денис Грушенцев(evilden), Максим Талиманчук (mtalimanchuk)

Это соревнование продолжение популярного конкурса от Jigsaw по определению токсичного текста, однако в данном случае тренировка происходит на английских данных, а тестирование на мультиязыковых (в том числе на русском). Оценка происходит по метрике ROC AUC. Команда взяла бронзу (132 место из 1621) с оценкой ROC AUC ~ 0,9463. Финальная модель представляла собой ансамбль из классификаторов:

  • XLMRoberta large
  • Naive Bayes
  • Bert base
  • Bert base multilingual
  • USE multilingual

XLMRoberta large с линейным слоем 1024*1 была обучена на базовом датасете с оптимизатором AdamW. Модель multilingual использовалась в базовом варианте (обучена на 16 языках) без дообучения. Использование Bert base было возможно за счет автоматического перевода тестового датасета на английский язык. Обучающая выборка была расширена за счет дополнительных датасетов.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.

On Bert Distillation


Никита Балаганский

Как известно, модели на основе архитектуры BERT, добиваясь впечатляющих оценок качества, все же сильно отстают по производительности. Это связано с тем, что BERT модель с больших количеством весов. Есть несколько способов уменьшения модели, один из них дистилляция. Идея дистилляции создать модель студента меньшего размера, которая бы повторяла поведение большой модели учителя. Тренировка русской модели студента проходила на четырех картах 1080ti в течение 100 часов, на датасете новостей. В итоге модель студента получилась в 1,7 раз меньше, чем оригинальна модель. Сравнение качества моделей студента и учителя было произведено на датасете для определения эмоциональной окраски текста Mokoron. Как результат, модель студента показала сопоставимое качество с моделью учителя. Скрипт тренировки был написан с применением пакета catalyst. Подробнее о проекте можно почитать на Medium.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.


Картинка: rasa.com

Open Data Science Question Answering


Илья Сироткин, Юрий Зеленский, Екатерина Карпова

Все началось с поста в ODS от Екатерины Карповой. Идея была достаточно амбициозная создать автоответчик на вопросы в ODS slack community на основе собранного датасета вопросов и ответов. Однако предварительный анализ выявил, что большинство из вопросов достаточно уникальны, и создание размеченной тестовой выборки для оценки качества задача довольно трудоемкая. Поэтому было принято решение для начала создать классификатор для определения принадлежности задаваемого вопроса к slack-каналу ODS. Он бы помог новичкам ODS задавать вопросы в соответствующей теме каналов. В качестве оценки качества была выбрана метрика pwROC-AUC.

В рамках проекта был произведен сравнительный анализ популярных моделей классификации текстов. Лучшая из них модель на основе RuBERT от DeepPavlov показала качество 0,995 pwROC-AUC. Такие высокие цифры качества модели свидетельствуют о высокой степени разделения (и разделимости) исходных данных. Единственный канал, вызывающий затруднения у всех опробованных моделей, _call_4_colaboration. Но почему именно он, выяснить пока не удалось.

Расправившись с этим заданием, команда не оставляет надежд вернуться к изначальной задаче ответов на вопросы пользователей ODS.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.

Russian Aspect-Based Sentiment Analysis


Дмитрий Бунин

В рамках данного проекта решалась задача определения тональности относительно заданного объекта в тексте (задача С из конкурса Dialogue Evaluation 2015). В качестве датасетов использовались как русские, так и английские данные. В своей основе сравнивались современные модели на основе архитектур ELMо (из пакета RusVectores) и BERT (из пакета DeepPavlov). Модель на основе ELMо + CNN на русском языке показала сопоставимое качество с лучшей моделью из соревнования, несмотря на небольшую тренировочную выборку и сильный дисбаланс данных.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.



Kaggle: Tweet Sentiment Extraction


Кирилл Герасимов

По условию соревнования, задача состояла в выделении ключевого слова или фразы из текста твита, которые бы определяли настроение этого твита. В качестве метрики качества использовалось значение word-level Jaccard Score. В этом соревновании все участники столкнулись с шумными данных и неоднозначной разметкой. В качестве базовой модели командой использовалась модель из публичного ноутбука на основе RoBERTa-base. Эта модель использует подход reading comprehension, при котором выделяются начало и конец ключевой фразы (с обязательным условием, чтобы конец был после начала). Согласно принятой традиции, ансамбль разнообразных моделей показывал скоры лучше, чем отдельные модели. Как результат, бронза (135 место из 2100). По опыту победителя соревнования, двухуровневое ансаблирование дает еще лучшие скоры.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.

Автоматическое решение ЕГЭ


Михаил Тетерин и Леонид Морозов

Цель этого проекта улучшение метрик качества на трех задачах cоревнования AI Journey 2019 (автоматическое решение ЕГЭ), а именно:

  • поиск главной информации в тексте;
  • определение значения слова в заданном контексте;
  • расстановка знаков препинания в предложениях.

По всем трем задачам удалось превзойти лучшее решение на соревновании. Во многом улучшения обусловлены использованием дополнительных данных для обучения. В решениях лучшее качество показали модели на основе RuBERT от DeepPavlov.

Презентация проекта доступна по ссылке.
GitHub проекта доступен по этой ссылке.



В этой статье мы постарались рассказать про часть проектов, которые были представлены на семинаре, но их, конечно же, было больше.

Спасибо всем, кто принимал активное участие в курсе и не сдался. Ну а тем, кто только учится и ищет интересные задачи в области NLP, мы рекомендуем рассмотреть DeepPavlov Contribute project. Будущее Conversational AI в ваших руках!
Подробнее..

Собираем Свой Суперкомпьютер Недорого

16.03.2021 14:17:52 | Автор: admin

thumbnail


Нынче никого не удивишь достижениями искусственного интеллекта машинного обучения (ML) в самых разных областях. При этом доверчивые граждане редко задают два вопроса: (i) а какая собственно цена экспериментов и финальной системы и (ii) имеет ли сделанное хоть какую-то целесообразность? Самым важным компонентом такой цены являются как ни странно цена на железо и зарплаты людей. В случае если это все крутится в облаке, нужно еще умножать стоимость железа в 2-3 раза (маржа посредника).


И тут мы неизбежно приходим к тому, что несмотря на то, что теперь даже в официальные билды PyTorch добавляют бета-поддержку ROCm, Nvidia де-факто в этом цикле обновления железа (и скорее всего следующем) остается монополистом. Понятно, что есть TPU от Google и мифические IPU от Graphcore, но реальной альтернативы не в облаке пока нет и не предвидится (первая версия CUDA вышла аж 13 лет назад!).


Что делать и какие опции есть, когда зачем-то хочется собрать свой "суперкомпьютер", но при этом не хочется платить маржу, заложенную в продукты для ультра-богатых [мысленно вставить комментарий про госдолг США, майнинг, крах Бреттон-Вудсткой системы, цены на здравоохранение в странах ОЭСР]? Чтобы попасть в топ-500 суперкомпьютеров достаточно купить DGX Superpod, в котором от 20 до 100 с лишним видеокарт. Из своей практики де-факто серьезное машинное обучение сейчас подразумевает карточки Nvidia в количестве примерно 8-20 штук (понятно что карточки бывают разные).


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


Видеокарта


Итак нам стало понятно, что нам нужны карточки Nvidia для вычислений. Но не торопитесь покупать карты Quadro или Tesla или покупать официальные сборки, потому что зачастую в сборках заложена маржа в 50-60%. Обращаю внимание также на то, что все "метрики" в этой статье приведены весьма примерные и условные (скорее коррелирующие с нашей ежедневной работой, цены меняются постоянно, а тренды нет), потому что всегда найдется какой-то вид нейросетей на каком-то особом модном виде тензоров от Гугла, где все будет работать не так. Также опустим и то, что из-за короны и бума майнинга розничные цены неадекватны, но как говорится "This time is not different" и можно всегда будет закупиться на дне пузыря.


Как ни странно, с точки зрения потребителя с картами все просто. Вообще есть довольно популярная и длинная статья про выбор и сравнение карточек, она довольно неплохая, но автор явно в силу своего бекграунда упускает некоторые вопросы админства и сравнивает целесообразность опций только с точки зрения первичного рынка США (и очень много букв). Полезную выжимку этой статьи я уже писал тут а для целей этой статьи выжимка уже более подробная и такая:


  • Карточки для обучения:


    • По критерию цена / качество при прочих равных игровые карточки всегда лучше "специализированных". Например я лично сравнивал самые мощные из доступных карт 3090 против А100. А100 "быстрее" 3090 примерно в 2 раза но по официальной цене дороже в 5-6 раз;
    • Рассматривать стоит игровые карточки начиная с поколения "Pascal" (серия 10), серия 20 всеми была признана неуспешной и дорогой, даже базовые карточки же архитектуры Ampere (серия 30*) превзошли флагманы прошлого поколения (спасибо AMD, которая "почти" догнала Nvidia);
    • Лучшая карта всех времен и народов подержанная 1080 Ti с Авито. Не нужно пугаться отсутствия гарантии или годового пробега (два или три года постоянного майнинга я бы не стал брать, касательно игр тут все попроще). Просто грамотно осматривайте и тестируйте карты при покупке, погоняйте "пушистый бублик" хотя бы минут 20, осмотрите маркировку карты, банально прочитайте что выдают дрова и бенчмарки. При должном обращении ресурс карточки составляет примерно 3-4 года постоянного использования (в сухом прохладном помещении, периодически выдувая пыль);
    • На пальцах топовые карты Ampere примерно в 2 раза быстрее 1080 Ti (а иногда и в 3). Мы даже не рассматривали покупку 3080 по банальной причине, что Nvidia зажала для них памяти (вероятно мотивируя пользователей 4K мониторов или использовать DLSS или покупать 3090). Причем я слышал странные слухи про 3080 с 16 или 20 GB памяти (в ноутбуках?);
    • Также немаловажно что в поколении 20* появились тензорные ядра, и хоть в игровых картах они в первую очередь предназначены для таких вещей как DLSS и как-то обрезаны, но тем не менее на части задач вкупе с использованием AMP или APEX они позволяют получить ещё прирост в скорости в два раза. Это объемная тема, я описывал свои мысли тут, и конечно читайте доку от Nvidia;

    Screenshot 2021-03-12 114522


    Кто знает, уточните что это такое вообще? Какие-то секретные склады Nvidia?

    • C 3090 с "турбиной" правда вышел казус, она вышла настолько удачной, что по слухам из-за того что "серьезные" люди стали предпочитать ее дорогим картам Tesla под давлением от Nvidia несколько производителей сняли ее с производства;

  • Карточки для продакшена:


    • Я сталкивался с большим количеством заблуждений касательно деплоя на карточках и отразил большую часть тут;
    • Вообще если нет особых требований от админов (или система допустим собирается в super-tower корпусе который вставляется в стойку), то можно использовать те же игровые карты;
    • Но если по какой-то причине вам реально нужны карты с низким TDP или реально однослотовые или пассивные то есть интересные однослотовые решения линейки Quadro RTX и старая Tesla T4, цена которой хоть как-то адекватна (до пузыря). Минус Quadro состоит только в несколько завышенной референсной цене;

  • Охлаждение:


    • Карточки серии Ampere "холодные" 3-4 3090, стоящие рядом, без каких-либо настроек не греются выше 70-75 градусов, когда 80-85 это норма для 1080 Ti;
    • Если карты будут стоять на "уголках" (без корпуса) или в корпусе для майнинга то по сути неважно какая там система охлаждения;
    • Если карты будут стоять рядом то неизбежно обязательно покупать карточки с "турбиной" (центробежный вентилятор, выталкивающий воздух из корпуса);
    • Особняком стоят карточки такого форм-фактора гибрид водянки и воздуха, но их и раньше было почти невозможно купить. Я пользовался ими немного у знакомого, они реально особо не греются выше 50 градусов;
    • Отдельно стоит кастомные однослотовые версии версии обычных карт с водянкой (пример). Понятно, что их тоже практически невозможно купить. А если делать самому, то тут сборка сразу становится нетривиальной (я интересовался, кастомная вода, установка радиатора, зачем-то реболлинг, кастомная водянка, знатоки уточните болячки таких билдов);

  • PCIE lanes:


    • Чем больше, тем лучше, но насколько PCIE 4.0 помогает я пока не понял, вроде и так ничего не тормозило никогда;
    • До 4 карт в 1 сервере вам абсолютно точно достаточно PCIE 3.0 8x на 1 карту;
    • По рассказам людей, на 6-8 картах, этого тоже в принципе достаточно;
    • Я не собирал сервера с кастомной водой на 7-8 карточек, поэтому мне тут тяжело сказать;
    • Читайте документацию процессора и материнской платы;

  • Питание:


    • Это миф, что нет нормальных консьюмерских блоков питания на 4 3090. Есть блоки питания Super Flower и Platimax на 1500-2000 Ватт, прекрасно зарекомендовавшие себя. И если вы завтра не выбираете железо, чтобы обслуживать ML задачи уровня условного ВК, то высока вероятность что для продакшена вам вообще хватит 1 сервера (с исследованиями сложнее). Так же для исследований совсем не нужно двойное резервирование по питанию;
    • Если по какой-то причине вы не можете купить один блок на 2000 ватт, то можно просто купить плату для синхронизации двух блоков по 1000 ватт;
    • Вообще утилиты Nvidia позволяют настроить потребление карт, но можно просто рассчитывать мощность из расчета 300 Вт в пике на 1 карточку + 30% запаса мощности блока питания;


Диски


hdd_vs_flash_trends


Источник: WDC: No SSD/HDD Crossover

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


Если коротко и немного с добавлением ML:


  • SSD скорее всего никогда не догонят по цене HDD;
  • Меньше какого-то размера нет смысла НЕ покупать NVME SSD;
  • Для медленной помойки и бекапов конечно нельзя НЕ использовать HDD (или даже внешнее хранилище);
  • Точка "перехода" из быстрого в медленное хранилище у всех будет разной, но на рынке сейчас есть довольно дешевые SATA3 SSD на 1-4 терабайта;

И раз уж мы собераем "дешевый" суперкомпьютер из нескольких нод, то можно к нему и собрать и сетевую помойку тоже недорого (раз, два, три). Дальше в принципе можно стандартными средствами Linux даже SSD подкачку сделать для RAID массива (я пока просто обходился десятым RAID на 10 Gbit сети для наших задач). Единственный момент нужно недорого найти 10 Gbit/s оборудование, с этим может быть сложнее, но многие топовые материнские платы сейчас имеют 2 10 Gbit/s порта и на рынке есть пара недорогих PCIE решений.


Материнская Плата, Шасси


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


  • Nvidia DGX и его аналоги от менее пафосных вендоров. Там все прекрасно, кроме цены. Если очень грубо прикидывать, там стоят самые дорогие компоненты, и сверху еще маржа примерно в два раза поверх цены этих компонентов;
  • Кастомные сборки от кастом шопов. Самый яркий пример это вот эта контора. По ним в принципе можно даже проектировать свои сборки (правда допустим в декстоп сегменте там могут быть старые материнские платы). Видно также, что более новые сборки там как раз доступны с 3080 и 3090. Минус такого подхода опять же такая компания хоть и на бумаге формально представляет "поддержку", но по анекдотам эта поддержка естественно не глобальная и решение проблем занимает время. Простым языком админить это все равно надо самому, никто не поедет решать вашу проблему в воскресенье именно в вашей стране. Единственная экспертиза таких ребят, которая не валяется на дороге, это взять на себя геморрой по сборке кастомной воды на 8 карт и дать на это гарантию, но опять же по анекдотам людей вода (а особенно в свете "холодных" Амперов) не стоит свеч. Появление таких кулеров как Ice Giant делает воду вообще менее привлекательной долгосрочно;
  • Сборки на основе серверных платформ от SuperMicro или Gigabyte (или любой крупной аналогичной фирмы). Раньше моя претензия к таким платформам была в том, что в разумных ценах там никогда не было NVME дисков и были сильно устаревшие сокеты процессоров Intel. Сейчас подтянулись новые серверные решения на базе AMD и минус по сути только в цене. Естественно "официально" поддерживаются только карты Tesla и нужна только ECC память и серверные процессоры (как правило дороже в 2-3 раза);
  • Сборки на основе "профессиональных" и "экстремальных" материнских плат на обычном консьюмерском железе. В качестве корпуса можно использовать просто любой качественный большой ATX корпус или даже корпус для майнинга;

Первую категорию мы смело отметаем, т.к. мы хотим все-таки экономить. Вторая и четвертая категории по сути идентичны, но мы не хотим платить 50% маржи за гарантию (которую при покупке новых деталей и так дает производитель) и "поддержку" (и какие-то детали проще купить подержанными, например те же 1080 Ti на первое время). Получается, что выбор на самом деле между специализированными серверными платформами и самостоятельной сборкой. Есть еще пятый вариант заколхолзить на основе Б/У или "пустого" серверного корпуса применив смекалку, но по сути этот вариант просто является адаптацией варианта четыре к установке в стойку, но нужно или иметь такие железки под рукой или знать где покупать и как проверять (мне пару раз предлагали по цене металлолома какие-то старые салазки но там всегда или не было посадочных мест под PCIE в нужном количестве, или было вопросы к питанию а колхозить не хотелось).


Если внимательно посмотреть на характеристики серверных шасси и "профессиональных" материнских плат, то можно найти несколько интересных закономерностей (по сути они и размер вашего бюджета будут диктовать ваш выбор):


  • В Intel сейчас любят кидаться камнями, но процессоры ThreadRipper от AMD по номинальной цене просто прекрасны и неплохо так внесли новую струю на рынок. Серверные решения на базе EPYC такой же процессорной мощности стоят просто в 2-3 раза дороже;
  • Существует много профессиональных материнских плат на 6-7 PCIE слотов или плат для энтузиастов с 4 двойными PCIE слотами. Но все современные интересные карточки (без кастомной воды) с турбиной занимают 2 слота. И производители карт (судя буквально по наличию только одной или двух таких карты за несколько лет) не заинтересованы делать однослотовые карты (а зачем? геймеру никогда не нужно больше 2-4 карт). Никто не запрещает взять материнскую плату на 6-7 слотов от ASUS, майнерский корпус (или просто уголки из Икеи) и собрать все аки майнер на райзерах (найти работающий на x8-x16 райзер это то еще развлечение). Но у такой системы будет несколько минусов нельзя вставить в стойку, райзеры у меня лично постоянно глючили и отваливались, опредленный колхоз, отсутствие удобной фурнитуры и повышенный уровень шума (при прочих равных). Далеко не все ДЦ принимают такие системы для хостинга;
  • Получается, что если совсем абстрагироваться от конкретных цен в моменте, то есть всего 3 интересных опции: (i) или полностью консьюмерская сборка желательно на не ушатанных картах со вторичного рынка реалистично тянущая 4-6 карт (вопрос готовы ли вы геморроиться на райзеры, уголки и / или корпуса для майнеров) (ii) очень похожая сборка, но допустим на базе super-tower от Gigabyte или SuperMicro (оно будет вставляться в стойку тут основная фишка в этом, но часть деталей будет дороже) (iii) сборка на основе серверной платформы;
  • Опция (i) максимально выгодна, если вы можете собрать N машин по 4-6 карт и может стоить в 3-5 раз дешевле опции (iii) за счет цены самого шасси, повышенной цены процессора и повышенной цены ECC RAM;
  • Опция (ii) или (iii) неизбежна, если у вас есть обязательные требования по установке в стойку (колхозные варианты с переделкой старых шасси тут опускаем, т.к. у меня нет опыта, но может кто-то из коммьюнити делала). В нагрузку вы получите скорее всего дублирование блока питания, но для исследований это просто не нужно;
  • Я бы предположил, что опция (iii) становится привлекательной, если почему-то вы хотите ставить сразу 8-12 видеокарт в один сервер;

Еще отдельно отмечу, что я не использовал однослотовые видеокарты Quadro RTX для обучения нейросетей, но чисто по характеристикам кажется, что две такие карты примерно эквивалентны одной 3090, было бы также интересно выслушать тех, кто пробовал, в комментариях.


basic_config_example


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

Процессор и Шасси


Тут на самом деле все просто. Процессор вы по сути выбираете выбирая материнскую плату (я описал основные моменты, которые кажутся мне важными).


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


Сеть


У меня пока не было потребности (ну или скажем так, мы всегда умудрялись оптимизировать свои расчеты), где нужно было бы соединять несколько нод для расчетов используя скажем DistributedDataParallel из PyTorch (на одной ноде все конечно прекрасно работает). Не могу оценить хватит ли для него "стандартных" 10 Gbit/s без установки дорогих сетевых карт на 40+ Gbit/s. Отдельный вопрос конечно что с этим делать, т.к. такая плата скорее всего займет еще один PCIE-слот.


Пока тут могу рассказать только про один хак в "профессиональных" и "экстремальных" материнках зачастую бывает 1-2 разъема по 10 Gbit/s (и иногда даже третий гигабитный). В совсем дешевом варианте (только цена патч-корда высокой категории, но на коротком расстоянии даже "плохие" патч-корды показывают 10 гигабит) две такие материнки можно соеденить напрямую друг с другом и получить "суперкомпьютер". Если таких разъема два, то можно в мастер ноду уже воткнуть два патч-корда. Но чтобы соединить сеть больше, уже придется найти 10 гигабитный свич (внезапно найти подержанный Mikrotik не проблема, но они обычно очень сложны в настройке).


Финальные Ремарки и Исправления Ошибок


Буду очень рад, если знающие люди, кто строил такие системы и сети поделятся в комментариях опытом, проблемами, результатами своих экспериментов и мотивацией при выборе своей платформы!


Об Авторе


Александр Вейсов основатель / владелец комании Силеро (silero.ai), небольшой независимой компании, которая занимается разработкой продуктов в сфере распознавания, синтеза речи и NLP. Публике Хабра Силеро может быть известна по датасету Open STT, моделям silero-models или VAD-у silero-vad. На российском рынке компания распространяет свои решения через прямые продажи / проекты и вендоров / системных интеграторов софта.

Подробнее..

Мои machine learning тулы для инвестирования

29.03.2021 16:17:23 | Автор: admin

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

Выбор компаний в портфель

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

Ниже приведены некоторые базовые моменты, на которые можно обращать внимание при формировании решения о покупке какой-либо акции.

Деятельность компании

Можно смотреть на то, чем занимается компания. Если есть вера в будущее электромобилей, то, например, можно посмотреть в сторону Tesla (далее из статьи будет понятно, что это может быть не самый лучший выбор). Если есть вера в биомед, то можно купить бумаги из соответствующего сектора. При этом, на мой взгляд, важно понимать, что конкретно делает компания, на чем основан ее бизнес. Например, если взять нефтяные компании, то они могут заниматься совершенно разными вещами - одни добывают сырье, другие его перерабатывают, третьи только транспортируют. Из-за этого некоторые события, происходящие в мире, сильно влияют на одних, но совсем не влияют на других. Условно, закрыли какой-то морской канал, и танкеру, чтобы доставить нефть, приходится делать крюк, следовательно лишние затраты для транспортной компании. При этом какому-нибудь переработчику нефти все равно.

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

Финансовые отчеты

Но помимо этого было бы неплохо знать - а как конкретно зарабатывает фирма? Откуда у нее основные источники дохода и как они распределены? К счастью, каждая компания, торгующаяся на бирже, обязана раз в квартал (четверть года) раскрывать информацию о своих финансах (так называемые финансовые отчеты). Чтобы найти такие отчеты, достаточно вбить в любом поисковике "company_name investor relations" и перейти на соответствующий раздел сайта компании. На картинке показан кусок такого отчета компании Apple за 4 квартал:

Из него можно понять, что выручка компании (net sales, часто её называют revenue) за квартал составила почти 111.5 миллиардов долларов, что больше, чем в аналогичном квартале год назад (91.8 млрд). Кроме того, 95.7 млрд из них приходится на продукцию компании (продажи iPhone, iPad и т.д.), а 15.7 - на сервисы (Apple Music, App Store и т.д.). Так же можно увидеть, что чистая прибыль компании составила 28.8 млрд, причем видно, как это число получилось :
Из net sales вычли cost of sales (непосредственные затраты на производство) и operating expenses (побочные затраты), а так же учли налоги (provision for income taxes).
111.4 - 67.1 - 10.8 - 4.8 = 28.7

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

Мультипликаторы

Часто бывает так, что нужно сравнить компании, понять, какая из них лучше. Например, было решено, что в портфель необходимо добавить компанию, производящую потребительские товары. Но таких компаний огромное количество, и все они разных размеров, демонстрируют совершенно разные revenue, net income и т.д. На помощь приходят мультпликаторы - производные величины, которые можно непосредственно сравнить.

P/E (price to earnings) - цена-прибыль. Вычисляется как отношение капитализации компании к её годовой прибыли. Другими словами, данный показатель говорит о том, сколько лет компания будет окупаться, если ее купить сейчас. Например, у Apple сейчас P/E~30. Значит, если (в теории) мы целиком купим эту компанию по текущей цене, то через 30 лет эта покупка себя отобьет. Итак, чем ниже P/E, тем "дешевле" компания, что, разумеется, хорошо (лучше я куплю бизнес, который окупится за 10 лет, чем за 20). При этом важно понимать, что для разных секторов средние P/E могут сильно разниться. Это объясняется тем, что от одних секторов ожидания выше, чем от других. Например, продуктовому ритейлеру почти нереально увеличить выручку в 10 раз, а поставщик какого-нибудь интернет-сервиса спокойно может кратно наращивать количество пользователей от года к году. Вот и выходит, что технологические компании по P/E стоят "дороже", чем, например, сырьевые.

D/E (Debt to Equity) - долг к собственному капиталу. Данный мультипликатор показывает, насколько высокая долговая нагрузка у компании. Понятно, что если долг слишком высокий, то выше риски банкротства компании и меньше у неё возможностей. Иногда компании со слишком высоким D/E называют "зомби", потому что результат их деятельности целиком идет на обслуживание долга.

ROE (Return On Equity) - рентабельность собственного капитала. Вычисляется как отношение чистой прибыли к собственному капиталу компании. Мультипликатор показывает, как компания способна генерировать прибыль за счет собственных средств.
Есть еще много других мультипликаторов, но я в основном пользуюсь только этими.

Машинное обучение

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

Данные

Понятно, что для написания нужных мне алгоритмов необходимы данные по фундаментальным показателям компаний за предыдущие кварталы (как в отчетах, только в одном месте и единообразно). Для американского рынка бесплатных источников я не нашел, но есть недорогой (около 30$) поставщик довольно качественных данных с удобным API. Кроме того, там же есть и посуточные базовые свечные данные.

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

downloader = QuandlDownloader(config, secrets, sleep_time=0.8) downloader.ticker_download('datatables/SHARADAR/SF1?ticker={ticker}',                           ticker_list,                           save_dirpath='data/core_fundamental',                           skip_exists=False,                           batch_size=10,                           n_jobs=2)downloader.ticker_download('datatables/SHARADAR/DAILY?ticker={ticker}',                           ticker_list,                           save_dirpath='data/daily',                           skip_exists=False,                           batch_size=5,                           n_jobs=2) 

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

class DataLoader:    def load_base_data(self) -> pd.DataFrame:        # returned pd.DataFrame should have ["ticker"] column    def load_quartely_data(self, tickers: List[str]) -> pd.DataFrame:        # returned pd.DataFrame should have ["ticker", "date"] columns    def load_daily_data(self, tickers: List[str]) -> pd.DataFrame:        # returned pd.DataFrame should have ["ticker", "date"] columns

Соответственно, предполагается, что load_base_data будет загружать основные данные про компании, которые не меняются со временем, вроде сектора, индустрии и т.д.
load_quartely_data будет загружать поквартальные данные (revenue, netincome и т.д.), при этом каждая строчка - отдельный квартал.

load_daily_data грузит дневную дату (например, ценовые свечи, дневную капитализацию). Для текущего поставщика данных используется класс SF1Data, реализующий данный интерфейс.

Честная стоимость компании

Итак, первая задача, которая у меня постоянно возникала и которую я не знал как решить - оценка адекватной стоимости компании. То есть, часто можно слышать фразы "эта компания переоценена", "слишком дорогая" или наоборот "сильно недооцененная, дешевая". Но как численно понять, сколько по-хорошему должна стоить компания? Кто-то может сказать "а разве не для этого и существует мультипликатор P/E?" и будет отчасти прав. Но. Часть компаний (особенно на ранних этапах) являются убыточными и для них мультипликатор вообще не определен. Или для какой-то компании сейчас мультипликатор высокий, но это не значит, что компания плохая, просто на данном этапе она может вкладываться в рост. И для меня, как для инвестора, это хорошо - да, компания могла бы получить высокую прибыль (а, соответственно, низкий P/E), если бы сократила расходы на маркетинг, например. Но тогда она не заполучила бы новых клиентов, не открыла новые точки и т.д. В результате это привело бы к тому, что в будущем прибыль компании была бы не такая большая, как если бы сейчас полученная прибыль направилась в развитие.

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

Признаки

Первым делом нужно соорудить некоторое представление компании по ее фундаментальным показателям. Логично предположить, что если компания зарабатывает по 100 млрд последние 10 кварталов, то она никак не может стоить 1 млрд (должна стоить гораздо дороже).

Аналогичная интуиция и с остальными показателями - если долг убывает со временем, значит дела в порядке (плюсик к капитализации). Если выручка растет за последние кварталы - значит компания развивается, это хорошо, и, соответственно, должно закладываться в цену. Все эти признаки легко покрываются с помощью подсчетов статистик вроде mean max min std и т.д. для последних, например, 2, 4, 10 кварталов. Кроме того, часто смотрят не только на то, растет выручка или нет, но и на темпы роста. Поэтому можно добавить статистики и по диффам - например, среднее значение того, на сколько процентов росла выручка. При этом логично, что все эти подсчеты можно делать для разных квартальных срезов компании: считать признаковое представление не только для текущего квартала, но и для предыдущих (параметр max_back_quarter), тем самым кратно увеличивая датасет. Ну и как результат, полученный класс для подсчета квартальных фичей и его использование:

fc1 = QuarterlyFeatures(columns=['revenue', 'netinc', 'debt'],  quarter_counts=[2, 4, 10],  max_back_quarter=5)fc1.calculate(data_loader, ['AAPL', 'INTC', 'F'])

Кроме того, при оценке стоимости компании важны и ее базовые характеристики. Например, как уже упоминал, технологические компании обычно оцениваются дороже. Аналогично, из разных индустрий средние оценки компаний тоже могут разниться. Поэтому был реализовал класс BaseCompanyFeatures, кодирующий подобные признаки с помощью лэйбл-энкодинга:

fc2 = BaseCompanyFeatures(cat_columns=['sector', 'sicindustry'])fc2.calculate(data_loader, ['AAPL', 'INTC', 'F'])

Ещё одним моментом, который бы хотелось учитывать при оценке компании, является подневная динамика движения цены акции компании за последнее время. Интуиция в том, что если стоимость компании стабильно растет, то инвесторы охотнее будут её покупать. При этом динамика должна представляться в нормализованном виде, чтобы избежать лика(нечестно определять стоимость компании, основываясь на стоимости компании). Соответствующий класс DailyAggQuarterFeatures (так же работает с квартальными слайсами компании и параметром max_back_quarter):

fc3 = DailyAggQuarterFeatures(    columns=['marketcap'],    agg_day_counts=[100, 200, 400, 800],    max_back_quarter=5)fc3.calculate(data_loader, ['AAPL', 'INTC', 'F'])

Для удобства комбинирования признаков был реализован класс FeatureMerger:

feature = FeatureMerger(fc1, fc2, on='ticker')feature = FeatureMerger(feature, fc3, on=['ticker', 'date'])feature.calculate(data_loader, ['AAPL', 'INTC', 'F'])

Таргет

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

def calculate(self, data_loader, info_df: pd.DataFrame) -> pd.DataFrame:  '''  info_df:    pd.DataFrame containing information of tickers and dates    to calculate targets for. Should have columns: ["ticker", "date"].    '''

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

info_df = pd.DataFrame([{'ticker':'AAPL', 'date':'2020-10-30'}])target = QuarterlyTarget(col='marketcap', quarter_shift=0)target.calculate(data_loader, info_df)

На самом деле, тут можно было бы сделать и другой таргет - сгладить капитализацию за будущие 30 дней, например. Интуиция в том, что непосредственно в день отчета цена может сильно скакать, а за месяц все более-менее устаканится и средняя капитализация будет более стабильной. Как раз для таких целей у меня написан DailyAggTarget класс таргета:

target = DailyAggTarget(    col='marketcap',    horizon=30,    foo=np.mean)target.calculate(data_loader, info_df)

Модель

С подобными признаками, как известно, хорошо работают градиентные бустинги. Их и будем использовать. Единственный момент, что распределение нашего таргета не очень хорошее - одни компании стоят сотни миллиардов долларов, другие миллионы. А модель должна уметь адекватно предсказывать для всех. Воспользуемся классической фишкой - логарифмированием таргета.

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

model = LogExpModel(lgbm.sklearn.LGBMRegressor())model.fit(X, y)model.predict(X)


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

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

model = GroupedOOFModel(ansamble,    group_column='ticker',    fold_cnt=5)model.fit(X, y) # X should contain 'ticker' columnmodel.predict(X)

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

Данный ансамбль реализован с интерфейсом, типичным для всех моделей:

base_models = [lgbm.sklearn.LGBMRegressor(), ctb.CatBoostRegressor()]ansamble = EnsembleModel(  base_models=base_models,     bagging_fraction=0.7,    model_cnt=20)ansamble.fit(X, y)ansamble.predict(X)

Итого, финальная модель, являющаяся комбинацией всех описанных выше классов:

base_models = [LogExpModel(lgbm.sklearn.LGBMRegressor()),               LogExpModel(ctb.CatBoostRegressor())]ensemble = EnsembleModel(    base_models=base_models,     bagging_fraction=0.7,    model_cnt=20)model = GroupedOOFModel(ensemble,    group_column='ticker',    fold_cnt=5)

Пайплайн

Итак, почти все готово для обучения:

  • feature - класс, реализующий подсчет фичей

  • target - класс, реализующий вычисление таргета

  • model - модель(в том числе инкапсулирующая в себе разделение для валидации)

Осталось собрать все это воедино и обучить, используя наши данные (а именно, класс SF1Data). Для данных целей был написан класс BasePipeline. Он скрывает в себе всю логику с расчетом фичей, таргетов, обучением модели и подсчетом метрики (кроме того, поддерживается режим с мульти-таргетом и мульти-метриками). При инференсе производит pd.DataFrame с результатом в колонке out_name.

data_loader = SF1Data('path/to/data')pipeline = BasePipeline(    feature=feature,     target=target,     model=model,     metric=median_absolute_relative_error,    out_name=['fair_marketcap'])pipeline.fit(data_loader, ticker_list)pipeline.execute(data_loader, ['INTC'])

Результат:

ticker

date

fair_marketcap

INTC

2021-01-22

4.363793e+11

INTC

2020-10-23

2.924576e+11

INTC

2020-07-24

3.738603e+11

INTC

2020-04-24

3.766202e+11

INTC

2020-01-24

4.175332e+11


Еще раз код всего пайплайна целиком(он же на гитхабе https://github.com/fartuk/ml_investment/blob/main/train/fair_marketcap.py):

Код
SAVE_PATH = 'models_data/fair_marketcap'OUT_NAME = 'fair_marketcap'CURRENCY = 'USD'MAX_BACK_QUARTER = 10BAGGING_FRACTION = 0.7MODEL_CNT = 20FOLD_CNT = 5QUARTER_COUNTS = [2, 4, 10]AGG_DAY_COUNTS = [100, 200, 400, 800]SCALE_MARKETCAP = ["4 - Mid", "5 - Large", "6 - Mega"]DAILY_AGG_COLUMNS = ["marketcap", "pe"]CAT_COLUMNS = ["sector", "sicindustry"]QUARTER_COLUMNS = [            "revenue",            "netinc",            "ncf",            "assets",            "ebitda",            "debt",            "fcf",            "gp",            "workingcapital",            "cashneq",            "rnd",            "sgna",            "ncfx",            "divyield",            "currentratio",            "netinccmn"         ]data_loader = SF1Data('path/to/data')tickers_df = data_loader.load_base_data(    currency=CURRENCY,    scalemarketcap=SCALE_MARKETCAP)ticker_list = tickers_df['ticker'].unique().tolist()fc1 = QuarterlyFeatures(    columns=QUARTER_COLUMNS,    quarter_counts=QUARTER_COUNTS,    max_back_quarter=MAX_BACK_QUARTER)fc2 = BaseCompanyFeatures(cat_columns=CAT_COLUMNS)# Daily agss on marketcap and pe is possible here because it # normalized and there are no leakage.fc3 = DailyAggQuarterFeatures(    columns=DAILY_AGG_COLUMNS,    agg_day_counts=AGG_DAY_COUNTS,    max_back_quarter=MAX_BACK_QUARTER)feature = FeatureMerger(fc1, fc2, on='ticker')feature = FeatureMerger(feature, fc3, on=['ticker', 'date'])target = QuarterlyTarget(col='marketcap', quarter_shift=0)base_models = [LogExpModel(lgbm.sklearn.LGBMRegressor()),               LogExpModel(ctb.CatBoostRegressor(verbose=False))]ensemble = EnsembleModel(    base_models=base_models,     bagging_fraction=BAGGING_FRACTION,    model_cnt=MODEL_CNT)model = GroupedOOFModel(ensemble,                        group_column='ticker',                        fold_cnt=FOLD_CNT)pipeline = BasePipeline(feature=feature,                         target=target,                         model=model,                         metric=median_absolute_relative_error,                        out_name=OUT_NAME)result = pipeline.fit(data_loader, ticker_list)print(result)pipeline.export_core(SAVE_PATH)        

Итак, удалось построить пайплайн, который выдает для квартальных срезов компаний оценки честной капитализации. Поиграться с результатами и посмотреть на fair marketcap для компаний американского рынка можно на странице http://fattakhov.site/company?ticker=AAPL . Для этого нужно ввести тикер интересующей компании и нажать кнопку Analyze. Ну и, собственно, как можно использовать полученный инструмент - смотреть на реальную капитализацию (синий график), на предсказанную честную капитализацию (оранжевый график) и считать компанию недооцененный, если оранжевый график лежит ниже синего и переоцененной в противном случае. Сами точки, соответственно, находятся на датах выходов квартальных отчетов. Проверим модельку на некоторых примерах:

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

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

Справедливое изменение капитализации после отчета

Идея следующего пайплайна, который я попробовал, заключается в следующем: пусть модель для честного определения капитализации может не учитывать некоторые скрытые причны того, почему та или иная компания стот столько, сколько она стоит. Но можно ли научить модель после выхода очередного отчета предсказывать, насколько должна была измениться стоимость компании? Кажется, что такая задача проще, потому что часто бывает, скрытые моменты, объясняющие рыночную стоимость, переходят из квартала в квартал. Ну вот нравится инвесторам покупать Теслу и ничего с этим не поделаешь.

Итак, вышел отчет компании, ее фундаментальные показатели как-то изменились (например, выручка выросла на 30%, прибыль выросла на 40% и т.д.). И по таким изменениям хотим предсказывать, а как по-хорошему должна была измениться капитализация.

Признаки

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

Реализовать подсчет нужных признаков можно с помощью класса QuarterlyDiffFeatures. В качестве параметра compare_quarter_idxs передаем [1, 4], так как хотим сравнить показатели с предыдущим кварталом и кварталом год назад. Класс посчитает относительные изменения показателей, находящихся в колонках columns:

fc = QuarterlyDiffFeatures(    columns=['revenue', 'netinc'],    compare_quarter_idxs=[1, 4],    max_back_quarter=5)fc.calculate(data_loader, ['AAPL', 'INTC', 'F'])

Таргет

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

target = QuarterlyDiffTarget(col='marketcap', norm=True)target.calculate(data_loader, info_df)

Модель

Навороты с ансамблем, разумеется, можно оставить, но нужно решить вопрос с валидацией. В данном случае совсем не обязательно группировать по компаниям, ведь предсказания относительные, а что будет с компанией в будущем по ее истории из прошлого - совсем непонятно. Однако тут есть другой момент - предсказывая изменение на текущий квартал, модель не должна знать про то, как в аналогичном квартале (и в будущем) изменились капитализации других компаний. Например, если вдруг случился мощный кризис, на фоне всеобщей паники капитализации всех компаний попадали даже при хороших отчетах. И модель по косвенным признакам поняла, что в данный момент кризис и занизила предсказания. Но во время инференса такой информации не будет, поэтому приходим к тому, что нужно делать time-series валидацию. А именно, сортируем все данные во времени, делим на N фолдов, обучаем модель на первом, предсказываем на второй. Обучаем модель на первых двух фолдах, предсказываем на третий. И так далее. Таким образом, делая предсказание на очередной квартал, мы не заглядываем в будущее.

Как и в случае с группировкой по фолдам, реализация time series валидации скрыта в классе модели TimeSeriesOOFModel:

model = TimeSeriesOOFModel(    base_model=lgbm.sklearn.LGBMRegressor(),    time_column='date',    fold_cnt=20)model.fit(X, y) # X should contain 'date' columnmodel.predict(X)

Пайплайн

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

код
SAVE_PATH = 'models_data/fair_marketcap_diff'OUT_NAME = 'fair_marketcap_diff'CURRENCY = 'USD'MAX_BACK_QUARTER = 10BAGGING_FRACTION = 0.7MODEL_CNT = 20FOLD_CNT = 5QUARTER_COUNTS = [2, 4, 10]COMPARE_QUARTER_IDXS = [1, 4]SCALE_MARKETCAP = ["4 - Mid", "5 - Large", "6 - Mega"]CAT_COLUMNS = ["sector", "sicindustry"]QUARTER_COLUMNS = [            "revenue",            "netinc",            "ncf",            "assets",            "ebitda",            "debt",            "fcf",            "gp",            "workingcapital",            "cashneq",            "rnd",            "sgna",            "ncfx",            "divyield",            "currentratio",            "netinccmn"         ]data_loader = SF1Data('path/to/data')tickers_df = data_loader.load_base_data(    currency=CURRENCY,    scalemarketcap=SCALE_MARKETCAP)ticker_list = tickers_df['ticker'].unique().tolist()fc1 = QuarterlyFeatures(    columns=QUARTER_COLUMNS,    quarter_counts=QUARTER_COUNTS,    max_back_quarter=MAX_BACK_QUARTER)fc2 = BaseCompanyFeatures(cat_columns=CAT_COLUMNS)fc3 = QuarterlyDiffFeatures(    columns=QUARTER_COLUMNS,    compare_quarter_idxs=COMPARE_QUARTER_IDXS,    max_back_quarter=MAX_BACK_QUARTER)feature = FeatureMerger(fc1, fc2, on='ticker')feature = FeatureMerger(feature, fc3, on=['ticker', 'date'])target = QuarterlyDiffTarget(col='marketcap')base_models = [lgbm.sklearn.LGBMRegressor(),               ctb.CatBoostRegressor(verbose=False)]ensemble = EnsembleModel(base_models=base_models,                          bagging_fraction=BAGGING_FRACTION,                         model_cnt=MODEL_CNT)model = GroupedOOFModel(ensemble,                        group_column='ticker',                        fold_cnt=FOLD_CNT)pipeline = BasePipeline(feature=feature,                         target=target,                         model=model,                         metric=median_absolute_relative_error,                        out_name=OUT_NAME)result = pipeline.fit(data_loader, ticker_list)print(result)pipeline.export_core(SAVE_PATH) 

Попробуем запустить полученный пайплайн на некоторых примерах. Опять же, посмотреть результат для других тикеров можно на странице http://fattakhov.site/company?ticker=AAPL (черный график). Итак, новый пайплайн выдет относительное предсказанное изменение для текущего квартала:

ticker

date

fair_marketcap_diff

INTC

2021-01-22

0.283852

INTC

2020-10-23

-0.021278

INTC

2020-07-24

-0.035124

INTC

2020-04-24

-0.098987

INTC

2020-01-24

0.198822

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

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

С теслой, однако, даже такая модель не может объяснить столь стремительный рост :)

Характеристика потенциальных рисков

Может быть случай, что все предыдущие модели в один голос говорят: "покупай, дёшево!", но из истории понятно, что стоимость данной акции сильно скачет вверх-вниз, что не совсем приятно. Совершая сделку, хочется понимать, а какой есть риск? До каких пределов может опуститься цена и с какой вероятностью? Можно было бы из истории сделать статистические оценки, но у нас же ML-тулы :) Поэтому сделаем еще один машинно-обученный пайплайн (в этом подходе есть надежда, что модель сможет самостоятельно детектировать неблагоприятные/сильно рискованные моменты)

Фичи

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

Таргет

С выбором таргета тут сложнее. Основная идея в том, что он должен показывать, насколько вероятно падение в ближайшее время и каким оно может быть по величине. В голову приходит что-то вроде стандартного отклонения, std-вниз, максимальной просадки и т.п. за какой-то будущий промежуток времению. Пока для примера можно ограничиться std-вниз. Формула расчета представлена ниже (x_down - все x, меньшие среднего):

\sqrt{\sum{\frac{(x_{down} - \overline{x})^2}{N-1}}}

Класс таргета для таких целей уже описывался ранее:

target = DailyAggTarget(    col='marketcap',    horizon=90,    foo=down_std_norm)

Модель

С моделью все понятно, берем максимальный ансамбль. При этом так же, как и в предыдущем примере, нужно использовать time-series валидацию (более того, это первая модель, которая должна оценивать будущее).

Пайплайн

Все тот же класс BasePipeline позволяет реализовать данный пайплайн (гитхаб версия).

код
SAVE_PATH = 'models_data/marketcap_down_std'OUT_NAME = 'marketcap_down_std'CURRENCY = 'USD'TARGET_HORIZON = 90MAX_BACK_QUARTER = 10BAGGING_FRACTION = 0.7MODEL_CNT = 20FOLD_CNT = 20QUARTER_COUNTS = [2, 4, 10]COMPARE_QUARTER_IDXS = [1, 4]AGG_DAY_COUNTS = [100, 200, 400, 800]SCALE_MARKETCAP = ["4 - Mid", "5 - Large", "6 - Mega"]DAILY_AGG_COLUMNS = ["marketcap", "pe"]CAT_COLUMNS = ["sector", "sicindustry"]QUARTER_COLUMNS = [            "revenue",            "netinc",            "ncf",            "assets",            "ebitda",            "debt",            "fcf",            "gp",            "workingcapital",            "cashneq",            "rnd",            "sgna",            "ncfx",            "divyield",            "currentratio",            "netinccmn"         ]data_loader = SF1Data(config['path/to/data'])tickers_df = data_loader.load_base_data(    currency=CURRENCY,    scalemarketcap=SCALE_MARKETCAP)ticker_list = tickers_df['ticker'].unique().tolist()fc1 = QuarterlyFeatures(    columns=QUARTER_COLUMNS,    quarter_counts=QUARTER_COUNTS,    max_back_quarter=MAX_BACK_QUARTER)fc2 = BaseCompanyFeatures(cat_columns=CAT_COLUMNS)fc3 = QuarterlyDiffFeatures(    columns=QUARTER_COLUMNS,    compare_quarter_idxs=COMPARE_QUARTER_IDXS,    max_back_quarter=MAX_BACK_QUARTER)fc4 = DailyAggQuarterFeatures(    columns=DAILY_AGG_COLUMNS,    agg_day_counts=AGG_DAY_COUNTS,    max_back_quarter=MAX_BACK_QUARTER)feature = FeatureMerger(fc1, fc2, on='ticker')feature = FeatureMerger(feature, fc3, on=['ticker', 'date'])feature = FeatureMerger(feature, fc4, on=['ticker', 'date'])target = DailyAggTarget(    col='marketcap',    horizon=TARGET_HORIZON,    foo=down_std_norm)base_models = [LogExpModel(lgbm.sklearn.LGBMRegressor()),               LogExpModel(ctb.CatBoostRegressor(verbose=False))]ensemble = EnsembleModel(base_models=base_models,                          bagging_fraction=BAGGING_FRACTION,                         model_cnt=MODEL_CNT)model = TimeSeriesOOFModel(ensemble,                           time_column='date',                           fold_cnt=FOLD_CNT)pipeline = BasePipeline(feature=feature,                         target=target,                         model=model,                         metric=median_absolute_relative_error,                        out_name=OUT_NAME)result = pipeline.fit(data_loader, ticker_list)print(result)pipeline.export_core(SAVE_PATH) 

Итак, пайплайн готов и выдает на выход предсказанные std-вниз (нормированные):

ticker

date

marketcap_down_std

INTC

2021-01-22

0.043619

INTC

2020-10-23

0.057673

INTC

2020-07-24

0.061062

INTC

2020-04-24

0.053481

INTC

2020-01-24

0.039370

Если считать предсказанное std верным, то можно посчитать различные доверительные интервалы и отобразить их в виде ступенчатого графика. Для примера возьмём компанию Carnival, так как она известна своими скачками.

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

Заключение

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

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

Возможно, напишу продолжение про то, как я конкретно составляю портфель, диверсифицирую по секторам, подбираю веса бумаг и т.д.

Подробнее..

Категории

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

  • Имя: Макс
    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