Hint
Перед прочтением этой статьи советую ознакомиться с предыдущей статьей о TensorFlowKit и поставить star репозиторию.
Я не люблю читать статьи, сразу иду на GitHub
GitHub: TensorFlowKit
GitHub: Example
GitHub: Другое
TensorFlowKit API
Посeтив репозиторий, добавьте его в «Stars» это поможет мне написать больше статей на эту тему.
GitHub: Example
GitHub: Другое
TensorFlowKit API
Посeтив репозиторий, добавьте его в «Stars» это поможет мне написать больше статей на эту тему.
![image](https://habrastorage.org/getpro/habr/post_images/4bd/003/1d3/4bd0031d34a70973fcb070c1dd975477.gif)
Начиная работать в сфере машинного обучения, мне было тяжело переходить от объектов и их поведений к векторам и пространствам. Сперва все это достаточно тяжело укладывалось в голове и далеко не все процессы казались прозрачными и понятными с первого взгляда. По этой причине все, что происходило внутри моих наработок, я пробовал визуализировать: строил 3D модели, графики, диаграммы, изображения и тд.
Говоря об эффективной разработке систем машинного обучения, всегда поднимается вопрос контроля скорости обучения, анализа процесса обучения, сбора различных метрик обучения и тд. Особая сложность заключается в том, что мы (люди) привыкли оперировать 2х и 3х мерными пространствами, описывая различные процессы вокруг нас. Процессы внутри нейронных сетей происходят в многомерных пространствах, что серьезно усложняет их понимание. Осознавая это, инженеры по всему миру стараются разработать различные подходы к визуализации или трансформации многомерных данных в более простые и понятные формы.
Существуют целые сообщества, решающие такого рода задачи, например Distill, Welch Labs, 3Blue1Brown.
TensorBoard
Еще до начала работы с TensorFlow я начал работать с TensorBoard пакетом. Оказалось, что это очень удобное, кросплатформенное решение для визуализации разного рода данных. Потребовалось пару дней, чтоб “научить” swift приложение создавать отчеты в формате TensorBoard и интегрировать в мою нейронную сеть.
Разработка TensorBoard началась еще в середине 2015 года в рамках одной из лабораторий Google. В конце 2015го Google открыл исходный код и работа над проектом стала публичной.
Текущая версия TensorBoard — это python пакет, созданный в помощь TensorFlow, который позволяет визуализировать несколько типов данных:
- Скалярные данные в разрезе времени, с возможностью сглаживания;
- Изображения, в том случае, если ваши данные можно представить в 2D, например: веса сверточной сети (они же фильтры);
- Непосредственно граф вычислений (в виде интерактивного представления);
- 2D изменение значения тензора во времени;
- 3D Гистограмма — изменение распределения данных в тензоре во времени;
- Текст;
- Audio;
Кроме того, существует еще проектор (projector) и возможность расширять TensorBoard при помощи плагинов, но об этом я рассказать не успею в этой статье.
Для работы нам понадобится TensorBoard на нашем компьютере (Ubuntu или Mac). У нас должен быть установлен python3. Я советую установить TensorBoard как часть TensorFlow пакета для python.
Linux:
$ sudo apt-get install python3-pip python3-dev
$ pip3 install tensorflow
MacOS:
$ brew install python3
$ pip3 install tensorflow
Запускаем TensorBoard, указав папку в которой мы будем хранить отчеты:
$ tensorboard --logdir=/tmp/example/
Открываем http://localhost:6006/
TensorFlowKit
Пример на GitHub
Не забудьте поставить «start» репозиторию.
Рассмотрим несколько случаев уже непосредственно на примере. Создание отчетов (summary) в формате TensorBoard происходит в момент конструирования графа вычислений. В TensorFlowKit я постарался максимально повторить python подходы и интерфейс, чтобы в дальнейшем можно было пользоваться общей документацией.
Как я уже сказал выше, каждый наш отчет мы собираем в summary. Это контейнер, в котором хранится массив value, каждый из которых представляет какое — либо событие, которое мы хотим визуализировать.
Summary в дальнейшем будет сохранен в файл на файловой системе, где его и прочтет TensorBoard.
![image](https://habrastorage.org/getpro/habr/post_images/a12/da2/473/a12da247321bf8b5d3a9360097a6e771.png)
Таким образом, нам необходимо создать FileWriter, указав граф, который мы хотим визуализировать и создать Summary, в который мы будем складывать наши значения.
let summary = Summary(scope: scope)
let fileWriter = try FileWriter(folder: writerURL, identifier: "iMac", graph: graph)
Запустив приложение и обновив страницу, мы уже можем видеть граф, который мы создали в коде. Он будет интерактивен, так что по нему можно перемещаться.
![image](https://habrastorage.org/getpro/habr/post_images/1ac/4c9/ed1/1ac4c9ed1c9e3b9deedbc692e6442941.png)
Далее, мы хотим видеть изменение некой скалярной величины во времени, например значение функции потерь (loss function or cost function) и accuracy нашей нейронной сети. Для этого добавляем выходы наших операций в summary:
try summary.scalar(output: accuracy, key: "scalar-accuracy")
try summary.scalar(output: cross_entropy, key: "scalar-loss")
Таким образом, после каждого шага вычислений нашей сессии, TensorFlow автоматически вычитает значения наших операций и передаст их на вход результирующего Summary, который мы сохраним в FileWriter (как это сделать я опишу ниже).
![image](https://habrastorage.org/getpro/habr/post_images/e9c/06b/5a0/e9c06b5a0ea3653da62364dd166bf6d2.png)
Также у нас в нейросети есть большее количество весов и предубеждений (bias). Как правило это различные матрицы достаточно большой размерности и анализировать их значения распечатывая крайне сложно. Будет лучше, если мы построим график распределений (distribution). Добавим в наш Summary еще и информацию о величине изменений весов, которую проделывает наша сеть после каждого шага обучения.
try summary.histogram(output: bias.output, key: "bias")
try summary.histogram(output: weights.output, key: "weights")
try summary.histogram(output: gradientsOutputs[0], key: "GradientDescentW")
try summary.histogram(output: gradientsOutputs[1], key: "GradientDescentB")
Теперь в нашем распоряжении визуализация того, как менялись веса и какими были изменения во время обучения.
![image](https://habrastorage.org/getpro/habr/post_images/d0c/c42/bd0/d0cc42bd0a22b5eac2503d804b1dbe9f.png)
![image](https://habrastorage.org/getpro/habr/post_images/cc2/fae/db5/cc2faedb5b9ee547a1c7938b3c3005ce.png)
Но это еще не все. Давайте действительно заглянем в устройство нашей нейронной сети.
Каждая картинка рукописного текста, полученная на вход, находит некое отражение в соответствующих ей весах. То есть, поданная на вход картинка умеет активировать определенные нейроны, тем самым имеет некий отпечаток внутри нашей сети. Напомню, что мы имеем 784 веса на каждый нейрон из 10. Таким образом, у нас 7840 весов. Все они представлены в виде матрицы 784x10. Попробуем развернуть всю матрицу в вектор и после этого “вытащить” веса, которые относятся к каждому отдельному классу:
let flattenConst = try scope.addConst(values: [Int64(7840)], dimensions: [1], as: "flattenShapeConst")
let imagesFlattenTensor = try scope.reshape(operationName: "FlattenReshape",
tensor: weights.variable,
shape: flattenConst.defaultOutput,
tshape: Int64.self)
try extractImage(from: imagesFlattenTensor, scope: scope, summary: summary, atIndex: 0)
try extractImage(from: imagesFlattenTensor, scope: scope, summary: summary, atIndex: 1)
…
try extractImage(from: imagesFlattenTensor, scope: scope, summary: summary, atIndex: 8)
try extractImage(from: imagesFlattenTensor, scope: scope, summary: summary, atIndex: 9)
Для этого добавим в граф еще несколько операций stridedSlice и reshape. Теперь, каждый полученный вектор добавим в Summary как картинку:
try summary.images(name: "Image-\(String(index))", output: imagesTensor, maxImages: 255, badColor: Summary.BadColor.default)
В разделе Images в TensorBoard мы теперь видим “отпечатки” весов, такими какими они были во время процесса обучения.
![image](https://habrastorage.org/getpro/habr/post_images/561/5d1/e69/5615d1e69ac754dfa7024a6fd88320b1.png)
Осталось только обработать наш Summary. Для этого нам надо соединить все созданные Summary в один и обработать его во время обучения сети.
let _ = try summary.merged(identifier: "simple")
В момент работы нашей сети:
let resultOutput = try session.run(inputs: [x, y],
values: [xTensorInput, yTensorInput],
outputs: [loss, applyGradW, applyGradB, mergedSummary, accuracy],
targetOperations: [])
let summary = resultOutput[3]
try fileWriter?.addSummary(tensor: summary, step: Int64(index))
Прошу обратить внимание, что в этом примере я не рассматриваю вопрос вычисления accuracy, он вычисляется на данных обучения. Вычислять его на данных для обучения неверно.
![image](https://habrastorage.org/getpro/habr/post_images/4bd/003/1d3/4bd0031d34a70973fcb070c1dd975477.gif)
![image](https://habrastorage.org/getpro/habr/post_images/583/8eb/845/5838eb8458d7d44f192768730fb06060.gif)
В следующей статье я постараюсь рассказать, как собрать одну нейросеть и запустить ее на Ubuntu, MacOS, iOS из одного репозитория.
AFH
А вы пробовали пользоваться tf.summary.tensor_summary? Или я не понимаю для чего оно предназначено или оно не работет. Можете подсказать как с этой штукой работать?
Roaming Автор
Вы говорите, о вызове метода на языке Python. Вся статья (как и предыдущая) рассказывает о том, как использовать TensorFlow в языке Swift.
AFH
Да, я понимаю, но ведь в Swift-библиотеке есть аналог этого метода? Приходилось вам им пользоваться?
Roaming Автор
О какой swift библиотеке вы говорите? Не существует официальной реализации (как и полноценной не официальной) TensorFlow для Swift.
Именно по этой причине я написал свою реализацию — TensorFlowKit.
AFH
Да, я её и имею в виду, но по сути это не так и важно, вопрос в равной степени относится и к самому tensorflow.
Вы пишите что
Соответственно меня и интересует есть ли в вашей библиотеке аналог tf.summary.tensor_summary, пробовали ли вы им пользоваться и есть ли там какие-то нюансы?
Roaming Автор
Да, в бибилиотеке TensorFlowKit (автором которой являюсь я), реализован аналог Python API (tf.summary.tensor_summary) класс Summary. Об этом статья и написана.
У меня складывается впечатление, что Вы не владеете темой TensorFlow in other languages. Советюую ознакомится с этой статьей.
AFH
А у вас получалось сохранять для tensorboard какие-нибудь данные через этот метод? Дело в том что теже .scalar .histogram работают отлично и отображаются через tensorboard а вот с tensor_summary у меня не получилось вывести данные. Если вас не затруднит можете показать пример?
Roaming Автор
Да, все что вы видите в этой статье реализовано полностью средствами Swift.
Скажите, на каком языке Вы пробовали и если можно, покажите пример того, что не работает.
AFH
Я пробовал на python:
При этом cross_entropy отображается также как и у вас — в виде графика, а вот тензоры я нигде не вижу.
Roaming Автор
Скорее всего, Вы имеете в виду Histogram:
Но это «свернутое» отображение в виде распределения:
Так, что будьте внимательны.
AFH
Нет histogram это другой метод, я имею ввиду tensor_summary
Roaming Автор
Что непосредственно вы хотите видеть, как это должно выглядеть?
![image](https://habrastorage.org/getpro/habr/comment_images/9c1/acf/08a/9c1acf08abb8ba477fd3cbf7a8998391.jpg)
У вас есть тенсор n*m (скорее всего вектор, n*1). Он изменяется во времени.
В TensodBoard нет представления для такой конструкции. Можно конечно поиграться с image. Но скорее всего ваши данные нельзя представить в виде image.
В идеале что — то такое должно быть.
Но такого нет.
AFH
Нет, я просто хочу сохранить тензор с данными (также как мы, например, сохраняем промежуточные изображения) чтобы потом через tensorboard посмотреть этот тензор просто в виде вектора/матрицы и т.п.
Я допускаю что я мог просто не так понять предназначение этого метода. Думал, может вы сталкивались и знаете зачем он нужен и как правильно пользоваться.
Roaming Автор
Сам summary это только контейнер для SummaryValue.