PyTorch: попытка вернуться по графику второй раз, но буферы уже освобождены. Укажите keep_graph = True - PullRequest
0 голосов
/ 16 июня 2020

Это сообщение об ошибке, которое я получаю, когда работаю с некоторыми синтетическими c данными. Я немного озадачен, потому что ошибка сохраняется, хотя я делаю то, что мне посоветовали. Может это как-то быть связано с тем, что я не указываю партию? Облегчит ли использование PyTorch Dataset проблему?

Вот мой код (я новичок в PyTorch, только сейчас его изучаю) - он должен воспроизводиться:

Создание данных:

x, y = np.meshgrid(np.random.randn(100) , np.random.randn(100))    
z = 2 * x + 3 * y + 1.5 * x * y - x ** 2 - y**2
X = x.ravel().reshape(-1, 1)
Y = y.ravel().reshape(-1, 1)    
Z = z.ravel().reshape(-1, 1)    
U = np.concatenate([X, Y], axis = 1)    
U = torch.tensor(U, requires_grad=True)    
Z = torch.tensor(Z, requires_grad=True)    
V = []

for i in range(U.shape[0]):        
    u = U[i, :]  
    u1 = u.view(-1, 1) @ u.view(1, -1)    
    u1 = u1.triu()    
    ones = torch.ones_like(u1)    
    mask = ones.triu()    
    mask = (mask == 1)    
    u2 = torch.masked_select(u1, mask)    
    u3 = torch.cat([u, u2])    
    u3 = u3.view(1, -1)    
    V.append(u3)

V = torch.cat(V, dim = 0)

Обучение модели

from torch import nn    
from torch import optim    
net = nn.Sequential(nn.Linear(V.shape[1], 1))    
criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

for epoch in range(50):  # loop over the dataset multiple times    
    running_loss = 0.0        
    i = 0
    for inputs , labels in zip(V, Z):
        # get the inputs; data is a list of [inputs, labels]

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)

        loss.backward(retain_graph = True)

        optimizer.step()

        # print statistics
        running_loss += loss.item()

        i += 1

        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

Сообщение об ошибке:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-143-2454f4bb70a5> in <module>
     25 
     26 
---> 27         loss.backward(retain_graph = True)
     28 
     29         optimizer.step()

~\Anaconda3\envs\torch\lib\site-packages\torch\tensor.py in backward(self, gradient, retain_graph, create_graph)
    193                 products. Defaults to ``False``.
    194         """
--> 195         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    196 
    197     def register_hook(self, hook):

~\Anaconda3\envs\torch\lib\site-packages\torch\autograd\__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     97     Variable._execution_engine.run_backward(
     98         tensors, grad_tensors, retain_graph, create_graph,
---> 99         allow_unreachable=True)  # allow_unreachable flag
    100 
    101 

RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

Не могли бы вы объяснить ошибку и исправить код?

1 Ответ

0 голосов
/ 16 июня 2020

Предположительно, вы не запускали повторно код создания данных после установки retain_graph=True, как в I Python REPL. Это сработает, но почти во всех случаях установка retain_graph=True не является подходящим решением.

Проблема в вашем случае заключается в том, что вы установили requires_grad=True для U, что означает, что все, что задействовано U в создании данных, будет записано в вычислительном графе, и при вызове loss.backward() градиенты будут распространяться через все это до U. После первого раза все буферы для градиентов из них будут освобождены, а второй откат назад не удастся.

Ни U, ни Z не должны иметь requires_grad=True, так как они не оптимизируются /научился. Только изученные параметры (параметры, передаваемые оптимизатору) должны иметь requires_grad=True, и, как правило, вам не нужно устанавливать его вручную, поскольку nn.Parameter обрабатывает это автоматически.

Вы также должны убедиться, что тензоры, которые вы создаете из данных NumPy, имеют тип torch.float (float32), поскольку массив с плавающей запятой NumPy обычно будет float64, что в большинстве случаев не нужно и просто медленнее по сравнению с float32, особенно на GPU. .

U = torch.tensor(U, dtype=torch.float)

Z = torch.tensor(Z, dtype=torch.float)

И удалите retain_graph=True из обратного вызова:

loss.backward()
...