#python #machine-learning #pytorch
Вопрос:
Я просматриваю учебник PyTorch и только что узнал о optimizer.step
том, как и как он обновляет параметры сети (здесь).
Есть ли способ, чтобы создать функцию, которая, когда есть градиент обновления , чтобы каждый тренируемый параметр (например.г веса), примет значение веса и потери, и умножьте это значение на какой-то процент, что, мол 90%
?
Так что если обновление должно быть: w1 -= lr * loss_value = 1e-5 * 50
я хочу, чтобы пройти через функцию перед обновлением и сделать его 1e-5 * 50 * 90%
def func(loss_value, percentage):
return loss_value * percentage #new update should be w1 -= loss_value * percentage
Пример модели:
import torch
import torch.nn as nn
import torch.optim as optim
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.fc1 = nn.Linear(1, 5)
self.fc2 = nn.Linear(5, 10)
self.fc3 = nn.Linear(10, 1)
def forward(self, x):
x = self.fc1(x)
x = torch.relu(x)
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Model()
opt = optim.Adam(net.parameters())
features = torch.rand((3,1))
opt.zero_grad()
out = net(features)
loss = torch.tensor(5) - torch.sum(out)
loss.backward()
# need to have the function change the value of the loss update before the optimizer?
opt.step()
Комментарии:
1. Почему бы просто не снизить скорость обучения? Или установите планировщик скорости обучения, который устанавливает ее на 90%, пока вы не сделаете один шаг?
2. Потому что я хочу, чтобы он учитывал индивидуальные веса, а не только 1 функцию (т. Е. 1 скорость обучения).
3. Значит, для разных весов у вас будут разные проценты?
4. Да, в значительной степени. Допустим, вес находится в диапазоне от 0 до 5, процент будет составлять 10%, от 5 до 20, 30% и т. Д. Вот почему мне нужна функция, а не 1 значение (например, планировщик скорости обучения/и т. Д.)
Ответ №1:
Я получил этот фрагмент кода от https://discuss.pytorch.org/t/how-to-modify-the-gradient-manually/7483/2 и слегка отредактировал его:
loss.backward()
for p in model.parameters():
weights = p.data
scales = def_scales(weights)
p.grad *= scales # or whatever other operation
optimizer.step()
Это проходит через каждый параметр в модели (между loss.backward() и ДО шага оптимизатора) и настраивает сохраненный градиент ПЕРЕД применением backprop.
Пример def_scales
будет выглядеть примерно так (ОЧЕНЬ некрасиво), где значения val-это сравниваемые значения параметров, а масштабы-желаемые значения масштабирования потерь:
def def_scales(weights,scales=[0.1,0.5,1,1],vals=[0,5,10,float('inf')]):
out = torch.zeros_like(weights)
for V,v in enumerate(vals[::-1]): #backwards because we're doing less than
out[weights<=v] = scales[len(scales)-V-1] #might want to compare to abs
return out
Комментарии:
1. Это выглядит потрясающе! Я проверю это через час или около того. Просто чтобы убедиться, что я понимаю,
p.grad *= scales
изменится значение обновления веса, и когда я позвонюoptimizer.step()
, оно уменьшит каждый вес на соответствующее значение? т. е.w1-=p1.grad *= scales1
? Кроме того, я не совсем понялbackwards because we're doing less than
. Можете ли вы объяснить эту часть?2. «Меньше, чем» в данном контексте означает » Это банально, но он просматривает значения в vals и сравнивает их с ними, чтобы установить значения в out. Я сделал это таким образом, чтобы каждое значение было равно 1 (для..
3. И да, optimizer.step() зависит от поля градации каждого параметра. См., например, код SGD здесь .
4. Понял! Большое спасибо!
Ответ №2:
Это совершенно ненужный шаг, так как вся цель скорости обучения состоит в том, чтобы взять небольшую часть градиента и обновить веса, поэтому я действительно не понимаю, что вы пытаетесь здесь сделать. кроме того, обновление весов не соответствует уравнению, которое вы написали, вам нужно понять базовое исчисление и алгоритм градиентного спуска. мы берем частичную производную от значения затрат/потерь с учетом весов, а затем умножаем ее на небольшое число (скорость обучения) и вычитаем ее из начальных весов. если вы занимаетесь классификацией и хотите придать больше значения одному классу, чем другому, вы можете использовать функцию потери фокуса.
Комментарии:
1. Я написал
loss_value
, чтобы посчитать частичную производную от веса потерь. Надеялся, что это будет иметь смысл, но, может быть, и нет. Следовательно, я считаю, что мои уравнения верны. Я хочу учитывать индивидуальные веса в функции, и именно поэтому я не просто создал 1 скорость обучения2. в вашем коде нет» loss_value», а «loss_value» может просто означать значение убытка, которое рассчитывается на основе определенных вами функций потерь. частные производные вычисляются в » loss.bakward ()». «loss.backward()» вычисляет dloss/dx для каждого параметра x, для которого requires_grad=True. Да, вы можете получить доступ к весам моделей и изменить их, но вы просто добавляете еще один дополнительный гиперпараметр для настройки, делая это, и это не служит какой-либо конкретной цели.