График бт с овуляцией пример


Виды графиков базальной температуры - Базальная температура

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

I тип - нормальный двухфазный

На таких графиках отмечается повышение температуры во вторую фазу цикла не менее чем на 0,4 С; заметно «предовуляторное» и «предменструальное» падение температуры. Длительность повышения температуры после овуляции составляет 12- 14 дней. Такая кривая типична для нормального двухфазного менструального цикла. Пример:

На этом графике видно предовуляторное западение на 12 день цикла (температура падает существенно за два дня до овуляции), а также предменструальное падение, начиная с 25 дня цикла.

II тип - эстроген-прогестероновая недостаточность

Имеется слабо выраженный подъем температуры во вторую фазу. Разница температур в первой и второй фазе составляет не более 0,2- 0,3 С. Такая кривая может свидетельствовать об эстроген-прогестероновой недостаточности. Пример:

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

III тип - недостаточность второй фазы

Базальная температура начинает повышаться только незадолго перед менструацией, при этом отсутствует «предменструальное» падение температуры. Вторая фаза цикла длится при этом менее 10 дней. Такая кривая характерна для двухфазного менструального цикла с недостаточностью второй фазы. Пример:

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

IY тип - ановуляторный

Монотонная кривая возникает когда нет выраженного подъема на протяжении всего цикла. Такой график отмечается при ановуляторном (овуляция отсутствует) цикле. Пример:

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

Y тип - эстрогенная недостаточность

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

Выводы делает гинеколог!

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

 

Как проводить глубокое изучение графиков с помощью сверточных сетей графов | Тобиас Сковгаард Джепсен

Формально сверточная сеть с графами (GCN) - это нейронная сеть, которая работает с графами. Учитывая граф G = (V, E) , GCN принимает в качестве входных данных

  • матрицу входных признаков N × F⁰ матрицу признаков, X, , где N - количество узлов, а F⁰ - это количество входных функций для каждого узла, а
  • - матричное представление N × N структуры графа, например, матрица смежности A G.[1]

Скрытый слой в GCN, таким образом, может быть записан как Hⁱ = f ( H ⁱ⁻¹, A )) где H ⁰ = X и f - это распространение [1]. Каждый уровень Hⁱ соответствует матрице признаков N × F , где каждая строка является представлением признаков узла.На каждом слое эти объекты объединяются, чтобы сформировать объекты следующего слоя с использованием правила распространения f . Таким образом, на каждом последующем уровне объекты становятся все более абстрактными. В этой структуре варианты GCN различаются только выбором правила распространения f [1].

Одно из простейших возможных правил распространения: [1]:

f ( Hⁱ , A ) = σ ( AHⁱWⁱ )

где Wⁱ - весовая матрица для слоя i , а σ - нелинейная функция активации, такая как функция ReLU.Весовая матрица имеет размеры F × Fⁱ ¹ ; другими словами, размер второго измерения весовой матрицы определяет количество функций на следующем уровне. Если вы знакомы со сверточными нейронными сетями, эта операция похожа на операцию фильтрации, поскольку эти веса разделяются между узлами в графе.

Упрощения

Давайте рассмотрим правило распространения на самом простом уровне.Пусть

  • i = 1 , s.t. f является функцией входной матрицы признаков,
  • σ является функцией идентичности, а
  • выбирает веса s.t. AH W ⁰ = AXW ⁰ = AX .

Другими словами, f ( X , A ) = AX .Это правило распространения, возможно, слишком простое, но мы добавим недостающие части позже. Кстати, AX теперь эквивалентен входному слою многослойного персептрона.

Пример простого графика

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

Простой ориентированный граф.

И ниже его представление матрицы смежности numpy .

 A = np.matrix ([
[0, 1, 0, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[1, 0, 1, 0]],
dtype = float
)

Далее нам нужны функции! Мы генерируем 2 целочисленных функции для каждого узла на основе его индекса.Это упрощает позднее подтверждение вычислений матрицы вручную.

 In [3]: X = np.matrix ([
[i, -i]
для i в диапазоне (A.shape [0])
], dtype = float)
XOut [3] : matrix ([
[0., 0.],
[1., -1.],
[2., -2.],
[3., -3.]
])

Применение распространения Правило

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

 In [6]: A * X 
Out [6]: matrix ([
[1., -1.],
[5., -5.],
[1., -1.],
[2., -2.]]

Что случилось? Представление каждого узла (каждой строки) теперь является суммой характеристик его соседей! Другими словами, сверточный слой графа представляет каждый узел как совокупность его окрестности. Я рекомендую вам проверить расчет самостоятельно. Обратите внимание, что в этом случае узел n является соседом узла v , если существует ребро от v до n .

Возможно, вы уже заметили проблемы:

  • Агрегированное представление узла не включает его собственные функции! Представление - это совокупность функций соседних узлов, поэтому только узлы, у которых есть цикл, будут включать свои собственные функции в совокупность.[1]
  • Узлы с большими степенями будут иметь большие значения в их представлении функций, а узлы с малыми степенями будут иметь маленькие значения. Это может вызвать исчезновение или взрыв градиентов [1, 2], но также проблематично для алгоритмов стохастического градиентного спуска, которые обычно используются для обучения таких сетей и чувствительны к масштабу (или диапазону значений) каждой из входных характеристик.

Далее я рассмотрю каждую из этих проблем отдельно.

Добавление петель

Чтобы решить первую проблему, можно просто добавить петлю к каждому узлу [1, 2].На практике это делается путем добавления единичной матрицы I к матрице смежности A перед применением правила распространения.

 In [4]: ​​I = np.matrix (np.eye (A.shape [0])) 
IOut [4]: ​​matrix ([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]
]) В [8] : A_hat = A + I
A_hat * X
Out [8]: matrix ([
[1., -1.],
[6., -6.],
[3., -3.],
[5., -5.]])

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

Нормализация представлений признаков

Представления признаков могут быть нормализованы по степени узла путем преобразования матрицы смежности A, путем умножения ее на матрицу обратной степени D [1].Таким образом, наше упрощенное правило распространения выглядит так [1]:

f ( X , A ) = D ⁻¹ AX

Посмотрим, что будет. Сначала вычисляем матрицу степеней.

 In [9]: D = np.array (np.sum (A, axis = 0)) [0] 
D = np.matrix (np.diag (D))
D
Out [9]: матрица ([
[1., 0., 0., 0.],
[0., 2., 0., 0.],
[0., 0., 2., 0.],
[0., 0., 0., 1.]
])

Прежде чем применять правило, давайте посмотрим, что произойдет с матрицей смежности после ее преобразования.

.

Veusz 2D Примеры

спектр


Постскриптум PDF SVG Документ Veusz

функций


Постскриптум PDF SVG Документ Veusz

несколько осей


Постскриптум PDF SVG Документ Veusz

гистограммы


Постскриптум PDF SVG Документ Veusz

тройной участок


Постскриптум PDF SVG Документ Veusz

контур


Постскриптум PDF SVG Документ Veusz

операций с наборами данных


Постскриптум PDF SVG Документ Veusz

профиль


Постскриптум PDF SVG Документ Veusz

гистограмма с датами


Постскриптум PDF SVG Документ Veusz Файл данных

сломанная ось


Постскриптум PDF SVG Документ Veusz

ось функционально связана с другой осью


Постскриптум PDF SVG Документ Veusz Файл данных (1.18+)

связанных наборов данных


Постскриптум PDF SVG Документ Veusz

изображение


Постскриптум PDF SVG Документ Veusz

гистограмма


Постскриптум PDF SVG Документ Veusz

участка


Постскриптум PDF SVG Документ Veusz

несколько участков


Постскриптум PDF SVG Документ Veusz

фитинговые данные


Постскриптум PDF SVG Документ Veusz

вложенных участков


Постскриптум PDF SVG Документ Veusz

штриховка


Постскриптум PDF SVG Документ Veusz

коробчатый участок


Постскриптум PDF SVG Документ Veusz

полярный участок


Постскриптум PDF SVG Документ Veusz

простая жизнь


Постскриптум PDF SVG Документ Veusz Рукописный сценарий

импорт


Постскриптум PDF SVG Документ Veusz Файл данных 1 Файл данных 2

Импорт CSV


Постскриптум PDF SVG Документ Veusz CSV файл

маркеров и полигонов


Постскриптум PDF SVG Документ Veusz

цветных точек


Постскриптум PDF SVG Документ Veusz

звездная карта


Постскриптум PDF SVG Документ Veusz

этикетки


Постскриптум PDF SVG Документ Veusz Файл данных

Формы


Постскриптум PDF SVG Документ Veusz

отфильтрованные данные


Постскриптум PDF SVG Документ Veusz

изолированные оси


Постскриптум PDF SVG Документ Veusz

векторное поле


Постскриптум PDF SVG Документ Veusz

гистограммы с этикетками


Постскриптум PDF SVG Документ Veusz Данные

Ось

со шкалой, заданной функцией


Постскриптум PDF SVG Документ Веуша (1.18+)

данные гистограммы


Постскриптум PDF SVG Документ Veusz

с использованием выражений (функций) существующих данных


Постскриптум PDF SVG Документ Veusz (1.18+)

Двумерные данные на нерегулярной сетке


Постскриптум PDF SVG CSV Документ Veusz (1.20+)

контура с маркированными линиями


Постскриптум PDF SVG Документ Веуша (1.21+)

n размерных наборов данных


Постскриптум PDF SVG Документ Veusz (1.25+)

графики с фиксированным соотношением сторон


Постскриптум PDF SVG Документ Veusz (1.18+)

математика


Постскриптум PDF SVG Документ Veusz

Вложение

embedexample.py

.

Как проводить глубокое изучение графиков с помощью сверточных сетей графов | Тобиас Сковгаард Джепсен

Часть 2: Полу-контролируемое обучение с помощью сверток спектральных графов

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

  1. Высокоуровневое введение в сверточные сети с графами
  2. Полу-контролируемое обучение с помощью сверток спектральных графов (это)

В предыдущем посте я дал общее представление о GCN и показал, как представление узлов обновляется на основе представления его соседей. В этом посте мы сначала получим более глубокое понимание агрегации, выполняемой во время довольно простых сверток графа, обсуждаемых в предыдущем посте.Затем мы переходим к недавно опубликованному правилу сверточного распространения графа, и я показываю, как реализовать и использовать его для полууправляемого обучения по задаче прогнозирования сообщества в Zachary’s Karate Club, небольшой социальной сети. Как показано ниже, GCN может изучать представления скрытых функций для каждого узла, который разделяет два сообщества на два достаточно сплоченных и разделенных кластера, несмотря на использование только одного обучающего примера для каждого сообщества.

Представления скрытых узлов Каратэ Клуба Захари в GCN в каждую тренировочную эпоху.

В моем предыдущем посте о GCN мы видели простую математическую основу для выражения распространения в GCN. Короче говоря, учитывая матрицу признаков N × F⁰ X и матричное представление структуры графа, например, матрицу смежности N × N A из G , каждая из которых скрыта слой в GCN может быть выражен как Hⁱ = f ( H ⁱ⁻¹, A )) где H ⁰ = X и f - это правило распространения.Каждый уровень Hⁱ соответствует матрице признаков N × F , где каждая строка является представлением признака узла.

Мы видели правила распространения вида

  1. f ( Hⁱ , A ) = σ ( AHⁱWⁱ ), и
  2. f ( Hⁱ , A ) = σ ( D ⁻¹ ÂHⁱWⁱ ) , где Â = A + I , I - это единичная матрица, а D ⁻¹ - матрица обратной степени для Â .

Эти правила вычисляют представление признака узла как совокупность представлений признаков его соседей перед его преобразованием с применением весов Wⁱ и функции активации σ . Мы можем сделать шаги агрегации и преобразования более явными, выразив правила распространения 1 и 2 выше как f ( Hⁱ , A ) = transform (aggregate ( A, Hⁱ ) ), Wⁱ ) где преобразование ( M , Wⁱ ) = σ ( MWⁱ ) Агрегат и ( A, Hⁱ ) = AHⁱ для правила 1 и агрегат ( A, Hⁱ ) = D ⁻¹ H для правила 2.

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

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

Чтобы исправить эти две проблемы, правило 2 сначала применяет самостоятельные циклы, добавляя единичную матрицу к A и агрегируя с использованием преобразованной матрицы смежности Â = A + I . Затем представления признаков нормализуются путем умножения на матрицу обратной степени D , превращая совокупное значение в среднее значение, где масштаб агрегированного представления признаков инвариантен к степени узла.

Далее я буду ссылаться на правило 1 как на , на правило сумм и на правило 2 как на правило , то есть на правило .

В недавней статье Кипфа и Веллинга предлагаются быстрые приближенные свертки спектрального графа с использованием правила спектрального распространения [1]:

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

Агрегирование как взвешенная сумма

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

Правило суммы
Чтобы увидеть, как вычисляется агрегированное представление признаков узла i -го с использованием правила суммирования, мы видим, как вычисляется i -я строка в агрегате.

Правило суммы как взвешенная сумма

Как показано выше в уравнении 1a, мы можем вычислить агрегированное представление признаков узла i -го как вектор-матричное произведение. Мы можем сформулировать это векторно-матричное произведение как простую взвешенную сумму, как показано в уравнении 1b, где мы суммируем по каждой из N строк в X .

Вклад j -го узла в совокупность в уравнении 1b определяется значением j -го столбца i -й строки A .Поскольку A является матрицей смежности, это значение равно 1, если узел j th является соседом узла i th, и в противном случае равно 0. Таким образом, уравнение 1b соответствует суммированию представлений признаков соседи и -го узла. Это подтверждает неофициальные наблюдения из предыдущего поста.

В заключение, вклад каждого соседа зависит исключительно от соседства, определенного матрицей смежности A .

Правило среднего значения
Чтобы увидеть, как правило среднего значения агрегирует представления узлов, мы снова видим, как вычисляется -я строка в агрегате, теперь с использованием правила среднего. Для простоты мы рассматриваем только правило среднего для «необработанной» матрицы смежности без добавления между A и единичной матрицей I , что просто соответствует добавлению петель в граф.

Правило среднего как взвешенная сумма

Как видно из приведенных выше уравнений, вывод теперь немного длиннее.В уравнении 2a мы сначала преобразуем матрицу смежности A , умножая ее на матрицу, обратную степени D . Это вычисление сделано более явным в уравнении 2b. Матрица обратной степени - это диагональная матрица, в которой значения по диагонали представляют собой обратные степени узла s.t. значение в позиции ( i, i) является обратной степенью i, -го узла. Таким образом, мы можем удалить один из знаков суммирования, получив Уравнение 2c.Уравнение 2c может быть дополнительно сокращено, давая уравнения 2d и 2e.

Как показано в уравнении 2e, мы снова суммируем по каждой из N строк в матрице смежности A . Как упоминалось при обсуждении правила сумм, это соответствует суммированию по каждому соседу -го узла. Однако теперь гарантируется, что весовые коэффициенты взвешенной суммы в уравнении 2e суммируются до 1 с степенью i -го узла. Таким образом, уравнение 2e соответствует среднему значению по представлениям признаков для соседей -го узла.

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

Спектральное правило
Теперь у нас есть полезная структура для анализа спектрального правила. Посмотрим, к чему это нас приведет!

Спектральное правило как взвешенная сумма

Как и в случае с правилом среднего, мы преобразуем матрицу смежности A, используя матрицу степеней D. Однако, как показано в уравнении 3a, мы возводим матрицу степеней в степень -0.5 и умножьте на каждую сторону A . Эта операция может быть разбита, как показано в уравнении 3b. Напомним еще раз, что матрицы степеней (и их степени) диагональны. Поэтому мы можем упростить уравнение 3b, пока не достигнем выражения в уравнении 3d.

Уравнение 3e показывает кое-что весьма интересное. При вычислении совокупного представления характеристик i-го узла мы принимаем во внимание не только степень i-го узла, но также степень j-го узла.

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

В дополнение к спектральному правилу Кипф и Веллинг демонстрируют, как GCN могут использоваться для полууправляемой классификации [1].В обучении с полу-контролем мы хотим использовать как помеченные, так и немаркированные примеры. До сих пор мы неявно предполагали, что доступен весь граф, т.е. что мы находимся в трансдуктивной среде. Другими словами, мы знаем все узлы, но не все метки узлов.

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

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

  1. Выполнить прямое распространение через GCN.
  2. Построчно примените сигмовидную функцию к последнему слою в GCN.
  3. Вычислите потерю кросс-энтропии для известных меток узлов.
  4. Обратное распространение потерь и обновление весовых матриц W на каждом уровне.

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

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

Zachary’s Karate Club

Вкратце, Zachary’s Karate Club - это небольшая социальная сеть, в которой возникает конфликт между администратором и инструктором в клубе карате. Задача - предугадать, какую сторону конфликта выберет каждый член клуба карате. Графическое представление сети можно увидеть ниже.Каждый узел представляет члена клуба карате, а связь между членами указывает, что они взаимодействуют вне клуба. Администратор и инструктор отмечены буквами A и I соответственно.

Zachary’s Karate Club

Свертки спектральных графов в MXNet

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

 класс SpectralRule (HybridBlock): 
def __init __ (self,
A, in_units, out_units,
активация, ** kwargs):
super ().__init __ (** kwargs) I = nd.eye (* A.shape)
A_hat = A.copy () + ID = nd.sum (A_hat, axis = 0)
D_inv = D ** - 0,5
D_inv = nd .diag (D_inv) A_hat = D_inv * A_hat * D_inv

self.in_units, self.out_units = in_units, out_units

с self.name_scope ():
self.A_hat = self.params.get_constant ('A_hat', A_hat)
self.W = self.params.get (
'W', shape = (self.in_units, self.out_units)
)
если активация == 'identity':
self.activation = lambda X: X
else:
сам.Activation = Активация (активация)

def hybrid_forward (self, F, X, A_hat, W):
aggregate = F.dot (A_hat, X)
spread = self.activation (
F.dot (aggregate, W))
return распространяться

__init__ принимает в качестве входных данных матрицу смежности A вместе с входной и выходной размерностью представления каждого узла из сверточного слоя графа; in_units и out_units соответственно. Петли добавляются к матрице смежности A посредством сложения с матрицей идентичности I , вычисления матрицы степени D и преобразования матрицы смежности A в A_hat , как указано спектральным правилом.Это преобразование не является строго необходимым, но является более эффективным с точки зрения вычислений, поскольку в противном случае преобразование выполнялось бы во время каждого прямого прохода уровня.

Наконец, в с предложением в __init__ мы сохраняем два параметра модели - A_hat сохраняется как константа, а весовая матрица W сохраняется как обучаемый параметр.

hybrid_forward - вот где происходит волшебство. В прямом проходе мы выполняем этот метод со следующими входными данными: X , выходом предыдущего уровня и параметрами A_hat и W , которые мы определили в конструкторе __init__ .

Построение сверточной сети на основе графа

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

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

Наконец, мы добавляем слой логистической регрессии поверх GCN для классификации узлов.

Реализация указанной выше архитектуры Python выглядит следующим образом.

 def build_model (A, X): 
model = HybridSequential () с моделью.name_scope ():
features = build_features (A, X)
model.add (features) classifier = LogisticRegressor ()
model.add (classifier) ​​model.initialize (Uniform (1)) return model, features

Я выделил часть сети для изучения признаков, которая содержит сверточные слои графа в компонент признаков и часть классификации в компонент классификатора . Отдельный компонент с функциями упрощает визуализацию активации этих слоев позже. LogisticRegressor в качестве уровня классификации, который выполняет логистическую регрессию, суммируя характеристики каждого узла, предоставленные последним сверточным слоем графа, и применяя сигмоидальную функцию к этой сумме.

Вы можете найти код для создания компонента features и код для LogisticRegressor в в прилагаемом блокноте Jupyter .

Обучение GCN

Код для обучения модели GCN можно увидеть ниже.Вкратце, я инициализирую двоичную функцию кросс-энтропийных потерь cross_entropy и оптимизатор SGD trainer для изучения сетевых параметров. Затем модель обучается для заданного количества эпох, где потерь вычисляются для каждого обучающего примера, а ошибка передается в обратном направлении с использованием loss.backward () . trainer.step Затем вызывается для обновления параметров модели. После каждой эпохи представление признаков, созданное слоем GCN, сохраняется в списке feature_presentations , который мы вскоре рассмотрим.

 def train (модель, особенности, X, X_train, y_train, эпохи): 
cross_entropy = SigmoidBinaryCrossEntropyLoss (from_sigmoid = True)
trainer = Trainer (
model.collect_params (), 'sgd' {learning_rate ':' sgd '{ , 'momentum': 1}) feature_presentations = [features (X) .asnumpy ()] для e в диапазоне (1, epochs + 1):
для i, x в перечислении (X_train):
y = array (y_train) [i]
с autograd.record ():
pred = model (X) [x] # Получить прогноз для образца x
loss = cross_entropy (pred, y)
loss.backward ()
trainer.step (1) feature_presentations.append (features (X) .asnumpy ()) return feature_presentations

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

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

Визуализация функций

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

Представление 1
В первом представлении мы просто используем разреженную матрицу идентичности 34 × 34, I , как матрицу признаков X , то есть - однократное кодирование каждого узла в графе . Это представление имеет то преимущество, что его можно использовать в любых графах, но оно дает входной параметр для каждого узла в сети, что требует значительного объема памяти и вычислительной мощности для обучения в больших сетях и может привести к переобучению.К счастью, сеть клубов карате довольно мала. Сеть обучена на 5000 эпох с использованием этого представления.

Ошибки классификации в клубе каратэ с использованием репрезентации 1

Коллективно классифицируя все узлы в сети, мы получаем распределение ошибок в сети, показанное выше. Здесь черный цвет указывает на неправильную классификацию. Хотя почти половина (41%) узлов классифицируется неправильно, узлы, которые тесно связаны либо с администратором, либо с инструктором (но не с обоими!), Как правило, классифицируются правильно.

Изменения в представлении признаков во время обучения с использованием представления 1

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

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

Представление 2
Мы улучшим представление 1, добавив две функции, которые не являются специфичными для какого-либо узла или области сети, но измеряют связь с администратором и инструктором.С этой целью мы вычисляем расстояние кратчайшего пути от каждого узла сети до администратора и инструктора и объединяем эти две функции с предыдущим представлением.

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

Классификационные ошибки в клубе карате с использованием репрезентации 1

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

Изменения в представлении признаков во время обучения с использованием представления 2

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

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

Я также показал, как реализовать и обучить GCN в MXNet для выполнения полууправляемой классификации на графах, используя свертки спектральных графов с Zachary's Karate Club в качестве простого примера сети. Мы увидели, как всего лишь используя два помеченных узла, GCN все еще может достичь высокой степени разделения между двумя сетевыми сообществами в пространстве представления.

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

.

Понимание PyTorch на примере: пошаговое руководство | Дэниел Годой

Фото Аллена Кая на Unsplash
Обновление

(15 июля 2020 г.): Сегодня я выпустил первых двух глав моей книги: Глубокое обучение с помощью PyTorch Пошаговое руководство: Руководство для начинающих .

Обновление (8 октября 2020 г.): Опубликована новая глава: «Простая задача классификации».

PyTorch - это самая быстрорастущая среда Deep Learning , которая также используется Fast.ai в его MOOC, Deep Learning for Coders и его библиотеке.

PyTorch также очень похож на pythonic , что означает, что его более естественно использовать, если вы уже являетесь разработчиком Python.

Кроме того, использование PyTorch может даже улучшить ваше здоровье. , по словам Андрея Карпати :-)

Существует , множество многих руководств по PyTorch , и его документация довольно полная и обширная. Итак, , почему вам следует продолжать читать это пошаговое руководство?

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

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

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

Большинство руководств начинается с красивой и красивой задачи классификации изображений , чтобы проиллюстрировать, как использовать PyTorch. Это может показаться крутым, но я считаю, что отвлекает вас от основной цели : как работает PyTorch ?

По этой причине в этом руководстве я остановлюсь на простой и знакомой проблеме: линейная регрессия с одной функцией x ! Это не намного проще… Модель простой линейной регрессии

Создание данных

Давайте начнем , генерируя некоторых синтетических данных: мы начнем с вектора из 100 точек для нашей функции x и создадим наши метки с использованием a = 1 , b = 2 и некоторого гауссова шума.

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

Создание синтетических наборов поездов и проверок для линейной регрессии Рисунок 1: Синтетические данные - Наборы обучения и проверки

Мы знаем , что a = 1 и b = 2, но теперь давайте посмотрим, насколько близко мы можем приблизиться к истинным значениям, используя градиентный спуск и 80 точек в обучении набор

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

Шаг 1. Вычислите потерю

Для задачи регрессии потеря определяется среднеквадратической ошибкой (MSE) , то есть средним значением всех квадратов разностей между метками (y) и предсказания (a + bx).

Стоит отметить, что если мы используем всех точек в обучающем наборе ( N ) для вычисления потерь, мы выполняем пакетный градиентный спуск .Если бы мы использовали единую точку каждый раз, это был бы стохастический градиентный спуск . Все остальное (n) между 1 и N характеризует градиентный спуск mini-batch .

Потеря: среднеквадратичная ошибка (MSE)

Шаг 2: Вычислить градиенты

Градиент является частной производной - почему частичное ? Потому что его вычисляют относительно (относительно) единственного параметра .У нас есть два параметра: a и b , поэтому мы должны вычислить две частные производные.

Производная сообщает вам , насколько данное количество изменяется , когда вы незначительно изменяете какое-то другое количество . В нашем случае, насколько изменится наш MSE loss , когда мы изменим каждого из двух наших параметров ?

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

Вычисление градиентов с коэффициентами a и b

Шаг 3: Обновление параметров

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

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

Обновление коэффициентов a и b с использованием вычисленных градиентов и скорости обучения

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

Шаг 4: Промыть и повторить!

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

Эпоха считается завершенной, если каждая точка уже была использована для вычисления потерь . Для пакетного градиентного спуска это тривиально, так как он использует все точки для вычисления потерь - одна эпоха то же самое, что одно обновление .Для стохастического градиентного спуска одна эпоха означает N обновлений , а для мини-пакета (размера n) одна эпоха имеет N / n обновлений .

Повторение этого процесса снова и снова в течение многих эпох - это, в двух словах, обучение модели.

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

Подождите ... Я думал, что это руководство о PyTorch!

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

Для обучения модели есть два шага инициализации :

  • Случайная инициализация параметров / весов (у нас всего два, , и b ) - строки 3 и 4;
  • Инициализация гиперпараметров (в нашем случае только скорость обучения и количество эпох ) - строки 9 и 11;

Убедитесь, что всегда инициализирует случайное начальное число , чтобы обеспечить воспроизводимость ваших результатов.Как обычно, случайное начальное число равно 42, наименьшее случайное число из всех случайных начальных чисел, которые можно было бы выбрать :-)

Для каждой эпохи есть четырех шага обучения :

  • Прогнозы вычислительной модели - это прямой проход - строка 15;
  • Вычислить потери, используя прогнозы , и , метки и соответствующую функцию потерь для текущей задачи - строки 18 и 20;
  • Вычислить градиента для каждого параметра - строки 23 и 24;
  • Обновите параметры - строки 27 и 28;

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

Реализация градиентного спуска для линейной регрессии с использованием Numpy

Чтобы убедиться, что мы не сделали никаких ошибок в нашем коде, мы можем использовать Scikit-Learn's Linear Regression , чтобы соответствовать модели и сравнить коэффициенты.

 # a и b после инициализации 
[0.49671415] [-0.1382643]
# a и b после нашего градиентного спуска
[1.02354094] [1.96896411]
# перехват и коэффициент из Scikit-Learn
[1.02354075] [1.96896447]

Они соответствуют до 6 знаков после запятой - у нас есть полностью работающая реализация линейной регрессии с использованием Numpy.

Пора TORCH it :-)

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

В глубоком обучении мы везде видим тензора . Фреймворк Google не зря называется TensorFlow ! Что такое тензор вообще?

Tensor

В Numpy у вас может быть массив , который имеет трех измерений , верно? То есть, технически говоря, тензор .

Скаляр (одно число) имеет нулевых измерений, вектор имеет одно измерение , матрица имеет два измерения , а тензор имеет три или более измерений . Это оно!

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

Рисунок 2: Тензоры - это просто многомерные матрицы :-) Источник

Загрузка данных, устройства и CUDA

Как нам перейти от массивов Numpy к тензорам PyTorch ”, спросите вы? Вот для чего подходит from_numpy .Однако он возвращает тензор ЦП .

« Но я хочу использовать свой навороченный графический процессор… », - скажете вы. Не беспокойтесь, это то, для чего подходит - () . Он отправляет ваш тензор на любое указанное вами устройство , включая ваш GPU (обозначаемый как cuda или cuda: 0 ).

« Что, если я хочу, чтобы мой код переключился на CPU, если GPU недоступен? ”, вы можете быть удивлены ... PyTorch снова вернулся - вы можете использовать cuda.is_available () , чтобы узнать, есть ли в вашем распоряжении графический процессор, и соответствующим образом настроить устройство.

Вы также можете легко преобразовать в более низкую точность (32-битное число с плавающей запятой), используя float () .

Загрузка данных: превращение массивов Numpy в тензоры PyTorch

Если вы сравните типов обеих переменных, вы получите то, что и ожидали: numpy.ndarray для первой и torch.Tensor для второй один.

А где же «живет» ваш симпатичный тензор? В вашем процессоре или графическом процессоре? Вы не можете сказать… но если вы используете PyTorch type () , он покажет свое местоположение - torch.cuda.FloatTensor - в данном случае тензор GPU.

Мы также можем пойти другим путем, превратив тензоры обратно в массивы Numpy, используя numpy () . Это должно быть просто, как x_train_tensor.numpy () , но

 Ошибка типа: невозможно преобразовать тензор CUDA в numpy. Используйте Tensor.cpu (), чтобы сначала скопировать тензор в память хоста. 

К сожалению, Numpy не может обрабатывать тензоры GPU… вам нужно сначала сделать их тензорами CPU, используя cpu () .

Создание параметров

Чем отличается тензор , используемый для данных - вроде тех, которые мы только что создали - от тензора , используемого в качестве ( обучаемого ) параметра / веса ?

Последние тензоры требуют вычисления его градиентов , поэтому мы можем обновить их значений (то есть значений параметров). Именно для этого подходит аргумент _grad = True .Он сообщает PyTorch, что мы хотим, чтобы он вычислял для нас градиенты.

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

Попытка создать переменные для коэффициентов…

Первый кусок кода создает два хороших тензора для наших параметров, градиентов и всего остального. Но это тензоры CPU .

 # FIRST тензор 
([- 0,5531], requires_grad = True) тензор
([- 0,7314], requires_grad = True)

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

 # ВТОРОЙ 
тензор ([0.5158], device = 'cuda: 0', grad_fn = ) тензор ([ 0,0246], device = 'cuda: 0', grad_fn = )

В третьем фрагменте мы сначала отправляем наши тензоры на устройства и , затем используем requires_grad_ () метод для установите его requires_grad на True на месте.

 # THIRD 
тензор ([- 0.8915], device = 'cuda: 0', requires_grad = True) tensor ([0.3616], device = 'cuda: 0', requires_grad = True)

В PyTorch, все методы что заканчивается символом подчеркивания ( _ ) вносит изменения на месте , то есть изменяет базовую переменную.

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

Фактическое создание переменных для коэффициентов :-)
 тензор ([0.6226], device = 'cuda: 0', requires_grad = True) tensor ([1.4505], device = 'cuda: 0', requires_grad = True) 

Много проще, правда?

Теперь, когда мы знаем, как создавать тензоры, требующие градиентов, давайте посмотрим, как PyTorch обрабатывает их - в этом роль…

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

Итак, как мы скажем PyTorch сделать свое дело и вычислить все градиенты ? Вот для чего подходит backward () .

Вы помните начальную точку для вычисления градиентов ? Это был убыток , так как мы рассчитали его частные производные относительно. наши параметры. Следовательно, нам нужно вызвать метод backward () из соответствующей переменной Python, например, loss.backward ().

Как насчет фактических значений из градиентов ? Мы можем проверить их, посмотрев на атрибут тензора grad .

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

Что означает знак подчеркивания ( _ ) в конце имени метода ? Ты помнишь? Если нет, вернитесь к предыдущему разделу и узнайте.

Итак, давайте откажемся от от ручного вычисления градиентов и вместо этого будем использовать методы backward () и zero_ () .

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

В первой попытке, если мы используем ту же структуру обновления, что и в нашем Код Numpy , мы получим странную ошибку ниже… но мы можем получить подсказку о том, что происходит, посмотрев на сам тензор - снова мы «потеряли» градиент при переназначении обновить результаты до наших параметров.Таким образом, атрибут grad оказывается None , и это вызывает ошибку…

 # FIRST ATTEMPT 
тензор ([0.7518], device = 'cuda: 0', grad_fn = )
AttributeError: объект «NoneType» не имеет атрибута «zero_»

Затем мы немного изменим его, используя знакомое на месте присвоение Python во второй попытке. И, опять же, PyTorch жалуется на это и выдает ошибку .

 # ВТОРАЯ ПОПЫТКА 
RuntimeError: конечная переменная, для которой требуется градиент, была использована в операции на месте.

Почему ?! Оказывается, случай «слишком много хорошего» . Виной всему является способность PyTorch построить динамический граф вычислений из каждой операции Python , которая включает любой тензор градиентных вычислений или его зависимости .

В следующем разделе мы углубимся во внутреннюю работу графа динамических вычислений.

Итак, как мы сообщаем PyTorch «отступить» и позволяем обновлять наши параметры , не нарушая его модный график динамических вычислений ? Вот что такое фонарик.no_grad () подходит для. Это позволяет нам выполнять обычные операции Python над тензорами , независимо от графа вычислений PyTorch.

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

 # ТРЕТЬЯ ПОПЫТКА 
тензор ([1.0235], device = 'cuda: 0', requires_grad = True) тензор ([1.9690], device = 'cuda: 0', requires_grad = True)

«К сожалению, никто можно сказать, что такое граф динамических вычислений.Вы должны увидеть это сами ». Morpheus

Насколько хорош был « The Matrix »? Верно-верно? Но, шутки в сторону, я хочу , вы с по тоже посмотрите график !

Пакет PyTorchViz и его метод make_dot (variable) позволяют нам легко визуализировать график, связанный с заданной переменной Python.

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

Вычисление MSE за три шага

Если мы позвоним по телефону make_dot (yhat) , мы получим t

.

Смотрите также