Можете ли вы обратить вспять нейронную сеть PyTorch и активировать входы с выходов? - PullRequest
3 голосов
/ 23 января 2020

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

Если я возьму базовый пример c NN из уроков PyTorch. Вот пример f(x,y) примера обучения.

import torch

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)

loss_fn = torch.nn.MSELoss(reduction='sum')

learning_rate = 1e-4
for t in range(500):
    y_pred = model(x)
    loss = loss_fn(y_pred, y)
    model.zero_grad()
    loss.backward()
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate * param.grad

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

Я не ожидаю, что y будет соответствовать исходным входам , которые обучались y выходы. Поэтому я ожидаю увидеть, какие функции активируются моделью для соответствия x и y.

Если это возможно, то как мне переставить модель Sequential без поломок? все веса и соединения?

Ответы [ 2 ]

1 голос
/ 23 января 2020

Это возможно, но только для очень особых случаев. Для сети с прямой связью (Sequential) каждый из слоев должен быть обратимым; это означает, что следующие аргументы применяются к каждому слою отдельно. Преобразование, связанное с одним слоем: y = activation(W*x + b), где W - матрица весов, а b - вектор смещения. Чтобы решить для x нам нужно выполнить следующие шаги:

  1. Reverse activation; не все функции активации имеют обратное значение. Например, функция ReLU не имеет обратного значения для (-inf, 0). Если мы использовали tanh с другой стороны, мы можем использовать его инверсию, которая 0.5 * log((1 + x) / (1 - x)).
  2. Solve W*x = inverse_activation(y) - b для x; для существования уникального решения W должен иметь одинаковый ранг строки и столбца, а det(W) должен быть ненулевым. Мы можем управлять первым, выбрав определенную c сетевую архитектуру, в то время как последняя зависит от процесса обучения.

Таким образом, чтобы нейронная сеть была обратимой, она должна иметь очень конкретную c архитектуру : все слои должны иметь одинаковое количество входных и выходных нейронов (т.е. матрицы с квадратным весом), и все функции активации должны быть обратимыми.

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

import torch

N = 10  # number of samples
n = 3   # number of neurons per layer

x = torch.randn(N, n)

model = torch.nn.Sequential(
    torch.nn.Linear(n, n), torch.nn.Tanh()
)

y = model(x)

z = y  # use 'z' for the reverse result, start with the model's output 'y'.
for step in list(model.children())[::-1]:
    if isinstance(step, torch.nn.Linear):
        z = z - step.bias[None, ...]
        z = z[..., None]  # 'torch.solve' requires N column vectors (i.e. shape (N, n, 1)).
        z = torch.solve(z, step.weight)[0]
        z = torch.squeeze(z)  # remove the extra dimension that we've added for 'torch.solve'.
    elif isinstance(step, torch.nn.Tanh):
        z = 0.5 * torch.log((1 + z) / (1 - z))

print('Agreement between x and z: ', torch.dist(x, z))
1 голос
/ 23 января 2020

Если я правильно понял, здесь есть два вопроса:

  1. Можно ли определить, какие функции на входе активировали нейроны?

  2. Если да, то возможно ли использовать эту информацию для генерации образцов из p(x|y)?

Относительно 1, основного c способа определения, является ли нейрон чувствителен к входной функции x_i - для вычисления градиента выходного сигнала этого нейрона относительно x_i. Высокий градиент будет указывать на чувствительность к конкретному элементу ввода. По этому вопросу имеется обширная литература, например, вы можете взглянуть на управляемое обратное распространение или на GradCam (последняя касается классификации с ловушками, но она содержит полезные идеи).

Что касается 2, я не думаю, что ваш подход к «решению проблемы» является правильным. Проблема в том, что ваша сеть является дискриминационной, и то, что она выводит, можно увидеть как argmax_y p(y|x). Обратите внимание, что это точечная оценка, а не полное моделирование распределения. Однако обратная проблема, которая вас интересует, - это выборка из

p(x|y)=constant*p(y|x)p(x).

. Вы не знаете, как производить выборку из p(y|x), и вы ничего не знаете о p(x). Даже если вы используете метод для обнаружения корреляций между нейронами и указанными c входными функциями, вы только обнаружили, какие функции более важны для предсказания сетей, но в зависимости от характера y это может быть недостаточно. Рассмотрим игрушечный пример, где ваши входные данные x представляют собой 2d точки, распределенные в соответствии с некоторым распределением в R^2, и где выходные данные y являются двоичными, так что любой (a,b) in R^2 классифицируется как 1, если a<1, и он классифицируется как 0, если a>1. Тогда дискриминирующая сеть может узнать вертикальную линию x=1 в качестве границы своего решения. Изучение корреляций между нейронами и входными функциями покажет, что только первая координата была полезна в этом прогнозе, но этой информации недостаточно для выборки из полного 2-мерного распределения входных данных.

Я думаю, что Вариационные автоэнкодеры могут быть тем, что вы ищете.

...