Интерактивное обучение моделей в Pytorch
Мне нужно тренировать две модели параллельно. Каждая модель имеет свою функцию активации с обучаемыми параметрами. Я хочу обучить модель 1 и модель 2 таким образом, чтобы параметры функции активации модели 1 (например, alpha1) отделялись от параметров модели 2 (например, alpha2) промежутком в 2; т.е. |alpha_1 - alpha_2| > 2. Интересно, как бы я мог включить это в функцию потерь для обучения.
1 ответ
Пример определения модуля
я использую torch.nn.PReLU
как параметрическая активация, о которой вы говорите.get_weight
создан для удобства.
import torch
class Module(torch.nn.Module):
def __init__(self, in_features, out_features):
super().__init__()
self.input = torch.nn.Linear(in_features, 2 * in_features)
self.activation = torch.nn.PReLU()
self.output = torch.nn.Linear(2 * in_features, out_features)
def get_weight(self):
return self.activation.weight
def forward(self, inputs):
return self.output(self.activation(self.inputs(inputs)))
Модули и настройка
Здесь я использую один оптимизатор для оптимизации параметров обоих модулей, о которых вы говорите. criterion
возможно mean squared error
, cross entropy
или что-то еще, что вам нужно.
module1 = Module(20, 1)
module2 = Module(20, 1)
optimizer = torch.optim.Adam(
itertools.chain(module1.parameters(), module2.parameters())
)
critertion = ...
Обучение
Вот один шаг, вы должны упаковать его в цикл для ваших данных, как это обычно делается, надеюсь, этого достаточно, чтобы вы поняли идею:
inputs = ...
targets = ...
output1 = module1(inputs)
output2 = module2(inputs)
loss1 = criterion(output1, targets)
loss2 = criterion(output2, targets)
total_loss = loss1 + loss2
total_loss += torch.nn.functional.relu(
2 - torch.abs(module1.get_weight() - module2.get_weight()).sum()
)
total_loss.backward()
optimizer.step()
Эта строка - это то, что вам нужно в этом случае:
total_loss += torch.nn.functional.relu(
2 - torch.abs(module1.get_weight() - module2.get_weight()).sum()
)
relu
используется так, чтобы сеть не извлекала бесконечную выгоду только от создания расходящихся весов. Если бы его не было, потери стали бы отрицательными, чем больше была бы разница между весами. В этом случае, чем больше разница, тем лучше, но она не имеет значения после того, как зазор станет больше или равен2
.
Возможно, вам придется увеличить 2
к 2.1
или что-то в этом роде, если вам нужно преодолеть порог 2
как стимул для оптимизации стоимости, когда она близка к 2.0
было бы маленьким.
редактировать
Без явно заданного порога это может быть сложно, но, возможно, что-то вроде этого сработает:
total_loss = (
(torch.abs(module1) + torch.abs(module2)).sum()
+ (1 / torch.abs(module1) + 1 / torch.abs(module2)).sum()
- torch.abs(module1 - module2).sum()
)
Это своего рода хакерство для сети, но, возможно, стоит попробовать (если вы примените дополнительные L2
регуляризация).
По существу, эта потеря будет оптимальной при -inf, +inf
пары гирь в соответствующих позициях и никогда не будут меньше нуля.
Для тех весов
weights_a = torch.tensor([-1000.0, 1000, -1000, 1000, -1000])
weights_b = torch.tensor([1000.0, -1000, 1000, -1000, 1000])
Убыток по каждой части составит:
(torch.abs(module1) + torch.abs(module2)).sum() # 10000
(1 / torch.abs(module1) + 1 / torch.abs(module2)).sum() # 0.0100
torch.abs(module1 - module2).sum() # 10000
В этом случае сеть может получить легкую выгоду, просто увеличивая веса с противоположными знаками в обоих модулях и игнорируя то, что вы хотите оптимизировать (большой L2
веса обоих модулей могут помочь, и я думаю, что оптимальное значение будет 1
/-1
в случае L2
с alpha
равно 1
), и я подозреваю, что сеть может быть очень нестабильной.
При использовании этой функции потерь, если сеть получает неверный знак большого веса, она будет серьезно наказана.
В этом случае вы останетесь с L2
Параметр alpha, который нужно настроить, чтобы заставить его работать, что не так строго, но все же требует выбора гиперпараметра.