Как в PyTorch случайным образом мутировать веса.

def mutate(self):
mut_prob = 0.3
mut_strength = 10
for param in self.parameters():
# Тут хитрые вычисления Создается тензон
# размерности с исходный тензор,
# он заполняется случайными значениями
# и сравнивается меньше ли он вероятности мутации, если True
# то True.int() = 1
# Иначе False.int() = 0
# ебучая магия
param.data += mut_strength * torch.randn_like(param) * (torch.rand(size=param.data.size()) < mut_prob).int()
Объяснение
Цикл обходит все тензоры, по каждому тензору он выполняет следующие действия:
Поэлементно инкрементирует тензор произведением трех переменных:
- сила мутации
- тензор той же размерности, заполненный случайными значениями в промежутке [0..1]
- тензор той же размерности, заполненный случайным образом нулями и единицами, единицы там просыпаны с управляемой вероятностью, потому что мы хотим управлять вероятностью мутирования весов.
Вот в этой последней величине нетривиальная магия.
(torch.rand(size=param.data.size()) < mut_prob).int()
Что тут происходит: сначала создается тензор заполненный случайными величинами.
Затем каждая величина проверяется на условие что она меньше вероятности мутации,
Получается тензон из булевых значений True/False, и чем ближе вероятность мутации к нулю, тем меньше будет True.
Затем этот тензор, как я понимаю, с помощью TORCH.TENSOR.INT() преобразуется к тензору, содержащему целочисленные значения. То есть:
tensor([[False, False],
[False, True],
[False, True]])
превращается в:
tensor([[0, 0],
[0, 1],
[0, 1]], dtype=torch.int32)
По сути, при этом умножении, получается маскирование нулями тензора со случайными величинами.
Вывод
Есть серьезное подозрение, что это должно делаться как-то проще, каким-то встроенным методом, но я не нашел. Либо, возможно, мутация весов вот таким варварским образом в корне неверна, я хз.
Как бы там ни было, может быть кому пригодится.