Итак, вы закончили обучение своей модели, и пришло время получить представление о том, чему она научилась. Вы сами решаете, какой тензор должен быть интересен, и идете искать его в своем коде — узнавать, как он называется. А потом до вас доходит — вы забыли дать ему имя. Вы также забыли обернуть блок логического кода именованной областью. Это означает, что вам будет трудно получить ссылку на тензор. Это справедливо как для скриптов Python, так и для TensorBoard:

Видите этот маленький красный круг, затерянный в море тензоров? Найти его сложно…
Это облом! Было бы намного лучше, если бы это выглядело примерно так:

Это больше походит на это! Каждый набор тензоров, образующих логическую единицу, заключен в именованную область.
Почему график не может быть автоматически построен таким образом, чтобы он напоминал ваш код? Я имею в виду, скорее всего, вы не построили модель, используя одну функцию, не так ли? Ваша кодовая база содержит несколько функций, каждая из которых образует логическую единицу, заслуживающую отдельной именованной области видимости!
Допустим, у вас есть тензор x которая была определена функцией fкоторый, в свою очередь, был вызван g. Это означает, что когда вы писали код, вы имели в виду эту логическую структуру: g -> f -> x. Было бы здорово, если бы модель автоматически строилась таким образом, чтобы имя тензора было g/f/x?
Если подумать, это довольно просто сделать. Все, что вам нужно сделать, это просмотреть все ваши функции и добавить одну строку кода:
def f():
with tensorflow.name_scope(‘f’):
# define tensors
Так что же не так с этим подходом?
- Название функции
fпоявляется дважды — как в объявлении функции, так и в качестве аргументаtensorflow.name_scope. Может быть, на следующей неделе вы измените название функции на что-то более осмысленное, скажем,foo. К сожалению, вы можете забыть обновить имя области видимости! - Вы должны применить отступ ко всему телу
f. Хотя это не так уж и плохо, лично мне не нравятся высокие уровни отступов. скажемf
содержит цикл for, который содержит оператор if, содержащий еще один цикл for. Благодаря звонку вtensorflow.name_scopeмы уже на уровне отступа 4!
Мы можем обойти эти недостатки, используя простое метапрограммирование — на помощь приходят декораторы Python!
import re
def name_scope(f):
def func(*args, **kwargs):
name = f.__name__[re.search(r’[^_]’, f.__name__).start():]
with tensorflow.name_scope(name):
return f(*args, **kwargs)
return func
@name_scope
def foo():
# define tensors
Как это работает? @ является синтаксическим сахаром. Это эквивалентно следующему:
def foo():
# define tensors
foo = name_scope(foo)
name_scope получает функцию в качестве аргумента (f) и возвращает новую функцию (func). func создает именованную область, а затем вызывает f.
Результат? Все тензоры, которые определяются f будет создан внутри именованной области. Имя области видимости будет именем исходной функции («foo») — благодаря f.__name__.
Одна небольшая проблема заключается в том, что хотя имена функций могут начинаться с «_», имена областей тензорного потока не могут. Вот почему мы должны использовать re.

Задача написания чистого кода тензорного потока незначительна по сравнению с исследовательской задачей сделать модель действительно хорошей.
Таким образом, легко поддаться искушению просто сосредоточиться на исследовательских аспектах вашей работы. Однако в долгосрочной перспективе важно не пренебрегать ремонтопригодностью и читабельностью вашего кода, в том числе графа.
Подход декоратора немного облегчает мою работу, и я надеюсь, что вы тоже извлечете из этого пользу. У вас есть другие советы, которыми вы хотели бы поделиться? Напишите строчку в комментариях!
Первоначально опубликовано мной на сайте engineering.taboola.com.
