How to solve the run time error "Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment"
Asked Answered
C

6

19

I want to use output variables of NN as an input in another function,but met with error like this 'Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment'.The out variables require gradient.

I tried by changing the output variables to numpy values, but in that case the back propagataion does not work because it see numpy values as variables which does not need gradient.

output = model(SOC[13])

# Three output values of NN
Rs=output[0]
R1=output[1]
C1=output[2]

# Using these variables in another function

num1=[Rs*R1*C1,R1+Rs]
den1=[C1*R1,1]
G = control.tf(num,den)

It should work, but it gives error.

     14             num=[Rs*R1*C1,R1+Rs]
     15             den=[C1*R1,1]
---> 16             G = control.tf(num,den)
~\Anaconda3\lib\site-packages\control\xferfcn.py in __init__(self, *args)
    106 
    107         """
--> 108         args = deepcopy(args)
    109         if len(args) == 2:
    110             # The user provided a numerator and a denominator.
~\Anaconda3\lib\site-packages\torch\tensor.py in __deepcopy__(self, memo)
     16     def __deepcopy__(self, memo):
     17         if not self.is_leaf:
---> 18             raise RuntimeError("Only Tensors created explicitly by the user "
     19                                "(graph leaves) support the deepcopy protocol at the moment")
     20         if id(self) in memo:
Canaanite answered 14/6, 2019 at 3:5 Comment(3)
if your receiving an error its typical to include the full stack trace and a pointer to the line in error (if not obvious from the trace).Pascha
LhasaDad: IncludedCanaanite
Add tags for the major packages that you are using.Ziegler
D
2

I met a similar problem once. To be brief, the mistake is caused by deepcopy, which is not suitable for non-leaf node. You can print the Rs, R1 and C1 to check whether they are leaf node.

If they are leaf node, there is "requires_grad=True" and is not "grad_fn=SliceBackward" or "grad_fn=CopySlices". I guess that non-leaf node has grad_fn, which is used to propagate gradients.

#---------------------------------------------------------------------------------
>>>import torch
>>>q = torch.nn.Parameter(torch.Tensor(3,3))
>>>q
Parameter containing:
tensor([[8.7551e-37, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00]], requires_grad=True)
#q is leaf node
>>>p = q[0,:]
>>>p
tensor([8.7551e-37, 0.0000e+00, 0.0000e+00], grad_fn=<SliceBackward>)
#p is non-leaf node
>>>q[0,0] = 0
>>>q
Parameter containing:
tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]], grad_fn=<CopySlices>)
#if slice operation is made on q, q becomes non-leaf node. The deepcopy is not suitable for q any more.
#-----------------------------------------------------------------------------
Dildo answered 25/12, 2019 at 13:12 Comment(0)
S
1

In pytorch, you can use the #tensor_name#.detach() function

new_tensor = _tensor_.detach()
Shaky answered 15/9, 2021 at 3:36 Comment(0)
J
1

In my case, what helped was to get rid of the registered buffer in

class PositionalEncodingLearned(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dropout = nn.Dropout(p=config.dropout)
        pe = nn.Parameter(torch.randn(size=(config.bptt, 1, config.emsize)))
        self.register_buffer('pe', pe)


    def forward(self, x: Tensor) -> Tensor:
        x = x + self.pe
        return self.dropout(x)

and change that to:

class PositionalEncodingLearned(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dropout = nn.Dropout(p=config.dropout)
        self.pe = nn.Parameter(torch.randn(size=(config.bptt, 1, config.emsize)))

    def forward(self, x: Tensor) -> Tensor:
        x = x + self.pe
        return self.dropout(x)
Juice answered 2/11, 2022 at 13:43 Comment(1)
In my case I don't want the positional encoding to be saved when making a checkpoint. Like so: self.register_buffer('pe', pe, persistent=False). Any other work around's?Explode
F
0

I used a dirty trick to solve this: save and load the tensor to/from disk, which creates another object:

def get_weights_copy(model):
    weights_path = 'weights_temp.pt'
    torch.save(model.state_dict(), weights_path)
    return torch.load(weights_path)
Fatherless answered 14/8, 2021 at 19:50 Comment(1)
lol cool trick!Bunnell
F
0

In my case, I was using .cuda with Parameter

I changed

self.x           = torch.nn.Parameter(x, requires_grad=True).cuda()

to

self.x           = torch.nn.Parameter(x, requires_grad=True)
Furnace answered 21/9, 2021 at 10:37 Comment(0)
S
0

Model-wise, i was trying to load some weights and then do fine-tuning with a deep copy of the model (used for the EMA- exponential moving average that is calling the copy.deepcopy(model)):

My 1-line solution

Add a decorator @torch.no_grad() in the function that loads the model weights or with the wrapper with torch.no_grad():

Stier answered 12/11, 2023 at 17:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.