Проблема Tensorflow / Keras со специальной архитектурой для машинного обучения на основе физики - PullRequest
0 голосов
/ 02 июля 2019

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

image

Как вы можете заметить, эта специальная архитектура позволяет нам оценивать дифференциальные операции, такие как K.gradients(model.outputs, model.inputs[0]), который является частной производной Txy относительно x , и иметь его как часть функции потерь.

Теперь я хотел бы иметь следующую архитектуру:

image

Как вы можете заметить, эта сеть имеет (x,y) в качестве входа, Txy в качестве выхода, за которым следуют операции градиента на Txy и затем (Uxy, V_xy) в качестве конечных выходов. Однако эта архитектура приводит к следующей ошибке:

raise ValueError('An operation has `None` for gradient. ')

Когда я проверяю градиенты потерь по отношению к весам, я обнаруживаю, что они равны None прямо на слоях, которые я определяю (Grad_Txy_x, Grad_Txy,y).

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


Отредактировано:

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

import numpy as np
import keras as k
import tensorflow as tf

def custom_gradient(y, x):
    return tf.gradients(y, x, unconnected_gradients='zero')

x = k.layers.Input(shape=(1,), name='x')
y = k.layers.Input(shape=(1,), name='y')

lay = k.layers.Dense(50, name='lay1')(k.layers.concatenate([x,y]))
lay = k.layers.Activation('tanh', name='tanh')(lay)

lay = k.layers.Dense(50, name='lay2')(lay)

Txy = k.layers.Dense(1, name='Txy')(lay)

dT_dx = k.layers.Lambda(lambda F: custom_gradient(F, x)[0], name='dTxy_dx')
dT_dx = dT_dx(Txy)

dT_dy = k.layers.Lambda(lambda F: custom_gradient(F, y)[0], name='dTxy_dy')
dT_dy = dT_dy(Txy)

lay = k.layers.Dense(50, name='lay3')(k.layers.concatenate([dT_dx, dT_dy]))
Uxy = k.layers.Dense(1, name='Uxy')(lay)
Vxy = k.layers.Dense(1, name='Vxy')(lay)

model = k.models.Model([x,y], [Uxy, Vxy])
model.compile(optimizer='adam', loss='mse')

k.utils.plot_model(model, show_shapes=False, to_file='output.png')

for lay in model.layers:
    print(k.backend.gradients(model.total_loss, lay.output))

model.fit([np.ones((10,1)), np.ones((10,1))],
          [np.ones((10,1)), np.ones((10,1))])

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

[<tf.Tensor 'gradients/concatenate_1/concat_grad/Slice:0' shape=(?, 1) dtype=float32>]
[<tf.Tensor 'gradients_1/concatenate_1/concat_grad/Slice_1:0' shape=(?, 1) dtype=float32>]
[<tf.Tensor 'gradients_2/lay1/MatMul_grad/MatMul:0' shape=(?, 2) dtype=float32>]
[<tf.Tensor 'gradients_3/tanh/Tanh_grad/TanhGrad:0' shape=(?, 50) dtype=float32>]
[<tf.Tensor 'gradients_4/AddN_1:0' shape=(?, 50) dtype=float32>]
[None]
[None]
[<tf.Tensor 'gradients_7/concatenate_2/concat_grad/Slice:0' shape=(?, 1) dtype=float32>]
[<tf.Tensor 'gradients_8/concatenate_2/concat_grad/Slice_1:0' shape=(?, 1) dtype=float32>]
[<tf.Tensor 'gradients_9/lay3/MatMul_grad/MatMul:0' shape=(?, 2) dtype=float32>]
[<tf.Tensor 'gradients_10/AddN:0' shape=(?, 50) dtype=float32>]
[<tf.Tensor 'gradients_11/loss/Uxy_loss/sub_grad/Reshape:0' shape=(?, 1) dtype=float32>]
[<tf.Tensor 'gradients_12/loss/Vxy_loss/sub_grad/Reshape:0' shape=(?, 1) dtype=float32>]

1 Ответ

0 голосов
/ 08 июля 2019

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

import numpy as np
import keras as k
import tensorflow as tf

def custom_gradient(y, x):
    return tf.gradients(y, x, unconnected_gradients='zero')

x = k.layers.Input(shape=(1,), name='x')
y = k.layers.Input(shape=(1,), name='y')

lay = k.layers.Dense(50, name='lay1')(k.layers.concatenate([x,y]))
lay = k.layers.Activation('tanh', name='tanh')(lay)

lay = k.layers.Dense(50, name='lay2')(lay)
#lay = k.layers.Activation('tanh')(lay)  


Txy = k.layers.Dense(1, name='Txy')(lay)
#Txy = k.layers.Activation('tanh')(Txy)


dT_dx = k.layers.Lambda(lambda F: custom_gradient(F, x)[0], name='dTxy_dx')
dT_dx = dT_dx(Txy)

dT_dy = k.layers.Lambda(lambda F: custom_gradient(F, y)[0], name='dTxy_dy')
dT_dy = dT_dy(Txy)

lay = k.layers.Dense(50, name='lay3')(k.layers.concatenate([dT_dx, dT_dy]))
Uxy = k.layers.Dense(1, name='Uxy')(lay)
Vxy = k.layers.Dense(1, name='Vxy')(lay)

model = k.models.Model([x,y], [Uxy, Vxy])
model.compile(optimizer='adam', loss='mse')

k.utils.plot_model(model, show_shapes=False, to_file='output.png')

for lay in model.layers:
    print(k.backend.gradients(model.total_loss, lay.output))

model.fit([np.ones((10,1)), np.ones((10,1))],
          [np.ones((10,1)), np.ones((10,1))])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...