How does AddmmBackward0 save its tensors

Akash_Guna_R.T: <p>I am trying to create a neural network with linear layers that are parallel to each other ( f1(x), f2(x)…) where f is a linear layer and x is the same input to all layers. In this case would a separate copy of x be stored and used for backpropagation of each layer? how do i view the implementation of AddmmBackward() (code).</p>

KFrank: <p>Hi Akash!</p>
<aside class="quote no-group" data-username="Akash_Guna_R.T" data-post="1" data-topic="188422" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/akash_guna_r.t/48/62352_2.png" class="avatar"> Akash_Guna_R.T:</div>
<blockquote>
<p>In this case would a separate copy of x be stored and used for backpropagation of each layer?</p>
</blockquote>
</aside>
<p>No.  <code>Linear</code> does need its input for the backward pass, but it keeps a reference<br>
to the original input tensor.  So all of the <code>f1, f2, ...</code> keep their own (python)<br>
reference, but all of these references refer to the same single tensor – no copies<br>
made.</p>
<p>(As an aside, if – at the cost of memory – <code>Linear</code> did make a copy of <code>x</code>, we would<br>
avoid the  dreaded <code>has been modified by an inplace operation</code> errors.)</p>
<p>Best.</p>
<p>K. Frank</p>

J_Johnson: <p>Effectively, you’re trying to perform multiple asynchronous linear operations on your inputs. In that case, I would think this would call for using the Parameter class. We can make one tensor with 3 dims that is appropriately matrix multiplied with the inputs to give out an identical operation as using separate linear layers. Please see the code below which you can test that demonstrates this method is an identical operation.</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn
from torch.nn.parameter import Parameter

num_para_layers = 3
input_size = 10
output_size = 1

# create uniform model weights that will be used in both methods
model_weight = torch.rand(num_para_layers, output_size, input_size)

#create a parameter tensor that will act as your parallel model weights as a control to check against
model = Parameter(model_weight)

#create a module list of separate linear layers with matching weights
layers = nn.ModuleList()

for i in range(num_para_layers):

    layer_weight = model_weight[i, ...]
    layer = nn.Linear(10, 1, bias=False)
    layer.weight.data = layer_weight
    layers.append(layer)

#create a dummy dataset
batch_size = 5
dummy_inputs = torch.rand((batch_size, input_size))

#get the parameter model outputs. If using a bias, make that a separate parameter of size (num_para_layers, output_size) and just add it to the function below
outputs1 = (model@dummy_inputs.T).permute(0,2,1)

#get the separate linear layer outputs
outputs2 = torch.empty((0, batch_size, 1))
for i in range(num_para_layers):
    subout = layers[i](dummy_inputs)
    outputs2 = torch.cat([outputs2, subout.unsqueeze(0)])

#print and compare the results
print(outputs1, outputs2)

#if this prints true, the math is effectively identical
print(torch.isclose(outputs2, outputs1).all())

</code></pre>
<p>Note that the Parameter class effectively creates layers that will be captured by autograd for training and can be optimized, just like any other layer. This method can be highly useful when you wish to create a new layer type out of the box and make use of the latest in parallel CUDA operations.</p>