Graph¶
Описание¶
Контейнер, представляющий топологию сети в виде графа.
Инициализация¶
def __init__(self, inputs, outputs, unsafe=False, nodesOnly=False, name=None):
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
inputs | Union[Node, list] | Входные узлы графа | - |
outputs | Union[Node, list] | Выходные узлы графа | - |
unsafe | bool | Включает/отключает безопасное размещение тензоров на GPU. | False |
nodesOnly | bool | Если True, то в атрибутах графа не будет сохранена информация об используемых в нём модулях. | False |
name | str | Имя контейнера. | None |
Пояснения
unsafe
- для некоторых модулей возможна перезапись их тензоров на GPU для экономии памяти. Если флаг unsafe
опущен, то будет производиться валидация графа на отсутствие участков, приводящих к нарушению целостности тензоров данных на GPU из-за флагов inplace
;
nodesOnly
- в атрибуте графа nodes
сохраняются данные о включённых в него узлах, а при опущенном флаге nodesOnly
в отдельном атрибуте modules
сохраняется информация о модулях, соответствующих этим узлам.
Методы¶
gatherTopology
¶
def gatherTopology(self, node, nodesOnly):
Собирает информацию о топологии графа, сохраняет её в атрибутах класса, а также при определённых условиях проводит валидацию графа на наличие участков, которые могут привести к нарушению целостности тензоров данных на GPU.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
node | Node | Объект класса-наследника Node, являющийся входной нодой графа. | - |
nodesOnly | bool | Если True, то в атрибутах графа не будет сохранена информация об используемых в нём модулях. | - |
Пояснения
-
getBlueprint
¶
def getBlueprint(self):
Формирует словарь, содержащий всю необходимую информацию о структуре графа для его восстановления при отсутствии кода.
Параметры
-
Пояснения
-
getNodeByName
¶
def getNodeByName(self, name):
Возвращает узел графа (объект класса-наследника Node) по его имени.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
name | str | Имя интересующего узла. | - |
Пояснения
-
optimizeForShape
¶
def optimizeForShape(self, shape, memlimit=None):
Производит оптимизацию графа под заданный входной размер.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
shape | tuple | Входной шейп, под который будет проводиться оптимизация. | - |
memlimit | int | Лимит выделяемой для оптимизации оперативной памяти. | None |
Пояснения
-
updateData
¶
def updateData(self, data):
Начиная с входных нод, производит последовательный проход по графу, применяя закреплённые за узлами операции над данными.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
data | tensor | Тензор входных данных. | - |
Пояснения
-
dataShapeFrom
¶
def dataShapeFrom(self, shape):
Вычисляет шейп данных после их прохода по графу.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
shape | Union[list, tuple] | Шейп входных данных. | - |
Пояснения
shape
- tuple, если один входной узел и List[tuple], если входных нод несколько.
graphDataShape
¶
def graphDataShape(self, shape, onmodule):
Базовый метод для вычисления шейпа данных после их прохода по графу. Принимает вспомогательную функцию как аргумент, предоставляя возможность проведения дополнительной операции при вычислении шейпов.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
shape | Union[list, tuple] | Шейп входных данных. | - |
onmodule | Callable | Дополнительная функция. | - |
Пояснения
shape
- см. dataShapeFrom;
onmmodule
- дополнительная функция, которая будет применяться при вычислениях шейпов; как правило, это функция оптимизации ноды под её выходной шейп.
backward
¶
def backward(self, grad, updParamGrads=True, updGrad=True, scale=1.0, momentum=0.0):
Начиная с выходных узлов, проходит по графу в обратном направлении, осуществляя алгоритм обратного распространения ошибки - вычисление градиентов на параметры узлов и на их входные данные.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
grad | tensor | Тензор градиента целевой функции. | - |
updParamGrads | bool | Флаг, регулирующий вычисление градиента на параметры узла. | True |
updGrad | bool | Флаг, регулирующий вычисление градиента на входные данные узла. | True |
scale | float | Масштаб: определяет, как сильно масштабировать градиент. | 1.0 |
momentum | float | Момент, коэффициент сохранения: определяет, сколько градиента нужно сохранить в этой итерации. | 0.0 |
Пояснения
-
gradShapeFrom
¶
def gradShapeFrom(self, shape):
Вычисляет шейп градиента на входных нодах графа.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
shape | Union[list, tuple] | Шейп градиента выходных узлов графа. | - |
Пояснения
-
updateGrad
¶
def updateGrad(self, grad):
Заглушка.
Параметры
Параметр | Возможные типы | Описание | По умолчанию |
---|---|---|---|
grad | tensor | Тензор градиента. | - |
Пояснения
-
reset
¶
def reset(self):
Обнуляет внутреннее состояние графа и его узлов (подробнее см. Node.reset)
Параметры
-
Пояснения
-
clearTraverse
¶
def clearTraverse(self):
Опускает флаги прохода
fwdVisited
и bwdVisited
для всех узлов графа.
Параметры
-
Пояснения
-
Примеры¶
Составим простой граф, выполняющий следующие операции:
- Два полносвязных входных слоя 'linear0' и 'linear1'
- Разбиение тензора данных после первого входного слоя на три блока 'split'
- Конкатенация двух блоков от первого тензора с тензором данных второго полносвзяного слоя 'concat0'
- Активация 'act' на конкатенации 'concat0'
- Финальная конкатенация 'concat1' оставшегося блока от 'split' и данных после активации 'act'
Необходимые импорты:
>>> import numpy as np
>>> from PuzzleLib.Backend import gpuarray
>>> from PuzzleLib.Containers import Graph
>>> from PuzzleLib.Modules import Linear, Split, Concat, Activation, relu
Info
gpuarray
необходим для правильного размещения тензора на GPU
Создание узлов будущего графа:
>>> v1 = Linear(10, 5, name="linear0").node()
>>> h1 = Split(axis=1, sections=(2, 2, 1), name="split").node(v1)
>>> v2 = Linear(10, 5, name="linear1").node()
>>> h2 = Concat(axis=1, name="concat0").node((h1, [1, 2]), v2)
>>> h3 = Activation(relu, name="act").node(h2)
>>> h4 = Concat(axis=1, name="concat1").node((h1, 0), h3)
Инициализация самого графа:
>>> graph = Graph(inputs=[v1, v2], outputs=h4)
Подготовка синтетических данных и их загрузка на GPU:
>>> v1data = gpuarray.to_gpu(np.random.randint(0, 255, (5, 10)).astype(np.float32))
>>> v2data = gpuarray.to_gpu(np.random.randint(0, 255, (5, 10)).astype(np.float32))
Прогон данных по графу:
>>> graph([v1data, v2data])
Подготовка данных (загрузка с GPU в оперативную память с помощью метода get
) со 'split' слоя и их вывод на экран. Метод round
здесь и далее используется только для упрощения визуального восприятия тензоров:
>>> splitData = [d.get() for d in graph["split"].data]
>>> for i, data in enumerate(splitData):
... print("split block {} results: \n{}".format(i, data.round(1)))
split block 0 results:
[[ -0.2 -59.7 11.9]
[-37.7 -75.4 21.1]
[-21.5 -23.8 30.9]
[-53.7 -60.4 46.5]
[-69.7 -60. 25.8]]
split block 1 results:
[[ -9.7 -8.7]
[ 47.2 -49.4]
[ 44.7 -69.7]
[ 21.2 -93.9]
[ 0.8 -31. ]]
split block 2 results:
[[130. ]
[141.3]
[ 99.6]
[135. ]
[112. ]]
Результаты с других слоёв:
>>> # 'linear1' layer results
>>> print(graph["linear1"].data.get().round(1))
[[-111.7 -16.6]
[-117.8 23.6]
[-101.4 29.1]
[ -86.7 30. ]
[-129.4 -22.5]]
>>> # 'concat0' layer results
>>> print(graph["concat0"].data.get().round(1))
[[ -9.7 -8.7 130. -111.7 -16.6]
[ 47.2 -49.4 141.3 -117.8 23.6]
[ 44.7 -69.7 99.6 -101.4 29.1]
[ 21.2 -93.9 135. -86.7 30. ]
[ 0.8 -31. 112. -129.4 -22.5]]
>>> # 'act' layer results
>>> print(graph["act"].data.get().round(1))
[[ 0. 0. 130. 0. 0. ]
[ 47.2 0. 141.3 0. 23.6]
[ 44.7 0. 99.6 0. 29.1]
[ 21.2 0. 135. 0. 30. ]
[ 0.8 0. 112. 0. 0. ]]
>>> # 'concat1' layer results
>>> print(graph["concat1"].data.get().round(1))
[[ -0.2 -59.7 11.9 0. 0. 130. 0. 0. ]
[-37.7 -75.4 21.1 47.2 0. 141.3 0. 23.6]
[-21.5 -23.8 30.9 44.7 0. 99.6 0. 29.1]
[-53.7 -60.4 46.5 21.2 0. 135. 0. 30. ]
[-69.7 -60. 25.8 0.8 0. 112. 0. 0. ]]