Вас укусила и Питорч, и математика. Во-первых, вам нужно
theta.grad = None
перед каждым шагом backward
. В противном случае градиенты накапливаются вместо того, чтобы перезаписывать предыдущие T
на каждом шаге. PyTorch не является символическим, в отличие от TensorFlow и T = t + theta
означает «T равно сумме тока t
и тока theta
», а не «T равно сумме t
и theta
, независимо от их значений в любое время в будущем ". С этими исправлениями вы получите следующий код:
def phaseOptimize(n, s = 48000, nsteps = 1000):
learning_rate = 1e-3
theta = torch.zeros(n, 1, requires_grad=True)
l = torch.linspace(0, 2 * np.pi, s)
t = torch.stack([l] * n)
T = t + theta
for jj in range(nsteps):
T = t + theta
loss = T.sin().sum(0).pow(2).sum() / s
theta.grad = None
loss.backward()
theta.data -= learning_rate * theta.grad.data
T = t + theta
print('Optimal theta: \n\n', theta.data)
print('\n\nMaximum value:', T.sin().sum(0).abs().max().item())
, который все равно не будет работать так, как вы ожидаете из-за математики.
Легко видеть, что минимум вашей функции потерь - это когда theta
также равномерно распределены по [0, 2pi)
. Проблема в том, что вы инициализируете свои параметры как torch.zeros
, что приводит к тому, что все эти значения равны (это полярная противоположность equispaced!). Поскольку ваша функция потерь симметрична относительно перестановок из theta
, вычисленные градиенты равны, и алгоритм градиентного спуска никогда не сможет «дифференцировать их». В более математических терминах вам не повезло инициализировать ваш алгоритм точно в седловой точке, поэтому он не может продолжаться. Если вы добавите какой-либо шум, он будет сходиться. Например, с
theta = torch.zeros(n, 1) + 0.001 * torch.randn(n, 1)
theta.requires_grad_(True)
Ваш код не будет работать, потому что Вы передаете класс Словаря значением. Это означает, что заключительное присвоение (dict = временный файл) не будет видимо к функции вызова. Не законно в C# пройти мимо дополнительных целей метода касательно или (в VB, законно сделать ByRef).
Вместо этого необходимо будет изменить встроенный Словарь. Попробуйте следующее
public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict,
Func<KeyValuePair<TKey,TValue>,bool> condition)
{
foreach ( var cur in dict.Where(condition).ToList() ) {
dict.Remove(cur.Key);
}
}
Править
Подкачанный порядок Где и ToList для сокращения размера выделенной памяти списка. Это теперь только выделит список для объектов, которые должны быть удалены.
public static void RemoveAll<TKey,TValue>(
this Dictionary<TKey,TValue> dict,
Predicate<KeyValuePair<TKey,TValue>> condition)
{
var toRemove = new List<TKey>();
foreach (var item in dict)
{
if (!condition(item))
toRemove.Add(item);
}
foreach (var key in toRemove)
{
dict.Remove(key);
}
}
Если количество ключей для удаления будет небольшим относительно размера словаря, то это будет быстрее (если удаленное число, вероятно, будет нулем, можно сделать это еще быстрее путем ленивого создания списка toRemove также.
Это сводится к тому же как обновленный ответ Jared, но позволяет Вам задерживать создание списка удаления если Вы, так требуйте. Если это не проблема (и у Вас нет причины для части точки останова путь посредством процесса), затем, Jared является более чистым и более простым.
Но если бы Вы хотели, то Вы могли бы возвратить новый и другой Словарь. Ваша подпись изменилась бы на это:
public static Dictionary<TKey, TValue> RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict,
Predicate<KeyValuePair<TKey,TValue>> condition)
И в коде вызова было бы сказано:
var newDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something"));
И, если бы Вы хотели изменить oldDict, то Вы назвали бы его как это:
oldDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something"));
Тот метод не будет работать, потому что "dict" параметр не передается ссылкой и на самом деле не может быть, потому что касательно не поддерживается как первый параметр дополнительного метода.
public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict,
Predicate<KeyValuePair<TKey,TValue>> condition)
{
var temp = new List<TKey>();
foreach (var item in dict)
{
if (!condition(item))
temp.Add(item.Key);
}
foreach (var itemKey in temp)
dict.Remove(itemKey)
}
Я хотел бы видеть реализации RemoveAllByKey и RemoveAllByValue также.