Дополнительный Словарь методов <TKey, TValue>.RemoveAll? Действительно ли это возможно?

Вас укусила и Питорч, и математика. Во-первых, вам нужно

  1. обнулить градиент, установив theta.grad = None перед каждым шагом backward. В противном случае градиенты накапливаются вместо того, чтобы перезаписывать предыдущие
  2. . Вам нужно пересчитывать 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)
7
задан Rob Stevenson-Leggett 17 March 2009 в 14:16
поделиться

4 ответа

Ваш код не будет работать, потому что Вы передаете класс Словаря значением. Это означает, что заключительное присвоение (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 для сокращения размера выделенной памяти списка. Это теперь только выделит список для объектов, которые должны быть удалены.

16
ответ дан 6 December 2019 в 08:45
поделиться
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 является более чистым и более простым.

4
ответ дан 6 December 2019 в 08:45
поделиться

Но если бы Вы хотели, то Вы могли бы возвратить новый и другой Словарь. Ваша подпись изменилась бы на это:

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"));
0
ответ дан 6 December 2019 в 08:45
поделиться

Тот метод не будет работать, потому что "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 также.

1
ответ дан 6 December 2019 в 08:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: