Блиц по PuzzleLib

Запустить в Google Colab

Roundicons.com Посмотреть на GitHub

Скачать ноутбук

Введение

PuzzleLib - это высокоуровневая нейросетевая библиотека, написанная на Python. Библиотека модульная и динамическая, дизайн навеян Torch и Chainer. Поддерживает вычисления на CPU (Intel/AMD) и GPU (NVIDIA/AMD).

PuzzleLib позволяет:

  • быстро и просто строить разнообразные архитектуры нейронных сетей;
  • использовать уже реализованные известные нейросетевые архитектуры, такие как VGG, ResNet, Inception, UNet и другие;
  • обучаться и работать и на GPU, и на CPU.

Установка библиотеки и зависимостей

Для подробной инструкции по установке библиотеки и зависимостей см. в документации раздел Windows для установки на ОС Windows и Linux для установки на Linux системы.

Если говорить в общем, то PuzzleLib поддерживает:

  • NVIDIA GPU (CUDA backend);
  • AMD GPU (ROCm backend);
  • Intel CPU (mkl-dnn backend);
  • AMD CPU (mkl-dnn/numpy backend);
  • Эльбрус CPU (частично)(numpy backend).

Функционал

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

from PuzzleLib.Modules import Linear, Activation
from PuzzleLib.Modules.Activation import relu

lin1 = Linear(insize=16, outsize=64)
act = Activation(activation=relu)
lin2 = Linear(insize=64, outsize=1)

Но блоки сети должны быть связаны между собой - для этого нужны контейнеры, например, Sequential:

from PuzzleLib.Containers import Sequential

seq = Sequential()

Добавлять новые слои в контейнер можно командой append:

seq.append(lin1)
seq.append(act)
seq.append(lin2)

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

from PuzzleLib.Containers import Graph

lin1 = lin1.node()
act = act.node(lin1)
lin2 = lin2.node(act)

graph = Graph(inputs=lin1, outputs=lin2)

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

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

from PuzzleLib.Optimizers.MomentumSGD import MomentumSGD

optimizer = MomentumSGD()
optimizer.setupOn(graph, useGlobalState=True)
optimizer.learnRate = 0.1
optimizer.momRate = 0.9

Для обучения еще надо определить функцию потерь, которая будет оценивать, насколько сеть ошиблась при классификации входного объекта. Допустим, это Abs:

from PuzzleLib.Cost import Abs

cost = Abs()

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

Чтобы запустить процесс обучения, создается тренер:

from PuzzleLib.Handlers import Trainer

trainer = Trainer(graph, cost, optimizer)

А для валидации сети - валидатор:

from PuzzleLib.Handlers import Validator

validator = Validator(graph, cost)

Заметьте, что валидатор не использует оптимизатор, в отличие от тренера.

И наконец, запуск обучения на 15 эпохах:

import numpy as np

data = np.random.randn(10000, 16).astype(np.float32)
labels = np.random.randn(10000, 1).astype(np.float32)

for i in range(15):
        trainer.trainFromHost(data[:8000], labels[:8000], macroBatchSize=400, \
                              onMacroBatchFinish=lambda train: print(f"Train error: {train.cost.getMeanError():.3f}")) 
        print(f"Epoch:{i+1:02}" f"\t Accuracy: {(1.0 - validator.validateFromHost(data[8000:], \
                              labels[8000:], macroBatchSize=400)):.3f}")

        optimizer.learnRate *= 0.9
Это обучение было на случайно сгенерированных данных, поэтому результаты получились довольно бессмысленные.

Приставка fromHost означает, что данные, которые мы передаём в метод trainFromHost, лежат в оперативной памяти CPU, и их сперва нужно загрузить на GPU. Если данные уже лежат на GPU, то можно использовать аналогичный метод train.

Параметр macroBatchSize нужен, чтобы указать, какое количество объектов из всей выборки за раз мы загрузим на GPU. Входные данные будут разделены на батчи, которые последоательно будут посылаться в нейронную сеть для обучения.

В параметре onMacroBatchFinish мы указываем, какую функцию нужно выполнить, когда macroBatch прошёл через сеть.