No acc change in custom Model despite param.requires_grad = True

username: pklo16
cooked: <p>Hello PyTorch Community! Glad to have you there.</p>
<p>I have problem with my custom model with which I’m stuck for almost 2 weeks.</p>
<p>My Model requires, lets say, N ordinary binary classifiers and 2 matrices which entries shall be parameters too. For x - entry data we try to get output for every classifier, tensorize it and then multiply given tensor with those matrices in a certain way.</p>
<p>I did create two classes outside main Model - BinaryClassifier and ProbMatrix, latter has matrix as a parameter, which is learnable. Separately nn.ModuleList = ClassifiersList with all BinaryClassifiers is created as a parameter of Model, then ProbMatrix1 and ProbMatrix2 out side of list. Parameters therefore are ModuleList(N*BinaryClassif.) and 2x ProbMatrix</p>
<p>In Model.forward(x) method Model runs operations:</p>
<ol>
<li>
<p>Create tensor Realisation of size N of (n-th BinaryClassifier(x)) by iterating ClassifiersList, then .repeat() it to get 2D-tensor</p>
</li>
<li>
<p>We set P as a result of algebraic operations on Realisation, ProbMatrix1.matrix and ProbMatrix2.matrix. For latter two i did implement method for substraction.</p>
</li>
</ol>
<p>3.Then we compute CrossEntropyLoss based on part of created Q, which is bigger tensor with P data copied. Both of those should NOT be parameters.</p>
<p>I really tried everything, requires_grad is True for all parameters, nevertheless no accuracy increase or decrease occurs. As i did some quick “print-debug” stuff I’m sure that there is problem with ProbMatrices, there is no change in parameters of those whatsoever.</p>
<p>Here I present some code, its a mess, but main question is - do I need to include those unwanted matrices as parameters? Give them require_grad = True? I can provide more code if needed.</p>
<p>Thank you a lot!</p>
<pre><code class="lang-auto">class BinaryNet(nn.Module):

    def __init__(self, input_shape):

        super(BinaryNet, self).__init__()

        self.LinearLayer1= Linear(input_shape, 1)
        nn.init.xavier_uniform(self.LinearLayer1.weight.data)

    def forward(self, x):
        x=torch.flatten(x)
        x=self.LinearLayer1(x)
        x=torch.squeeze(x)
        x=torch.sigmoid(x)
        return x

</code></pre>
<pre><code class="lang-auto">class ProbabilityMatrix(nn.Module):

    def __init__(self, c_count,l_count) -&gt; None:
        super(ProbabilityMatrix, self).__init__()
        self.classifleaves_size = c_count+l_count
        self.classif_size = c_count
        self.matrix = Parameter(torch.Tensor(self.classifleaves_size,self.classif_size))
        self.reset_parameters()
        
    def reset_parameters(self) -&gt; None:
        nn.init.kaiming_uniform_(self.matrix, a=math.sqrt(5))
    def extra_repr(self)-&gt;str:
        return 'Classifiers + Leaves = {}, Classifiers = {}'.format(
            self.classifleaves_size, self.classif_size)
    
    def substract_prob_matrices(a,b):
        return torch.sub(a.matrix,b.matrix)
</code></pre>
<pre><code class="lang-auto">class Graph(nn.Module):

    def __init__(
            self,
            l_count,
            c_count,
            step_count,
            input_shape,
            use_cuda=False):

        super(Graph, self).__init__()

        self.l_count = l_count
        self.c_count = c_count
        self.step_count = step_count
        self.input_shape = input_shape

        self.M0matrix = ProbabilityMatrix(c_count, l_count)
        self.M1matrix = ProbabilityMatrix(c_count, l_count)
        self.classifiers_list = nn.ModuleList()

        for i in range(c_count):
            model = BinaryNet(input_shape)
            self.classifiers_list.append(model)

    def forward(self, x):

        binary_realisation = Tensor([model.forward(x).item(
        ) for model in self.classifiers_list[0:self.c_count]]).repeat(self.l_count+self.c_count, 1)

        P_Matrix = binary_realisation * (self.M0matrix.matrix -  self.M1matrix.matrix) + self.M0matrix.matrix

        Q_Matrix = torch.ones(
            (self.l_count+self.c_count, self.l_count+self.c_count), requires_grad=True)
        for col in range(self.l_count+self.c_count):
            if(col &lt; self.c_count):
                for row in range(self.l_count+self.c_count):
                    with torch.no_grad():
                        Q_Matrix[row][col] = P_Matrix[row][col]
            else:
                for row in range(self.c_count):
                    with torch.no_grad():
                        Q_Matrix[row][col] = 0.

        final_vec = torch.zeros(
            (self.l_count+self.c_count, 1), requires_grad=True)
        with torch.no_grad():
            final_vec[0] = 1

            for step in range(self.step_count):
                final_vec = torch.matmul(Q_Matrix, final_vec)

            final_leaf = final_vec[self.l_count:]
            final_leaf = torch.unsqueeze(final_leaf, 0)
            final_leaf = torch.squeeze(final_leaf, 2)
            final_leaf = torch.tensor(final_leaf, requires_grad=True)
        return final_leaf
</code></pre>
<pre><code class="lang-auto"></code></pre>

username: ptrblck
cooked: <p>I’m not familiar with your use case, but note that rewrapping tensors in new tensors will detach them from the computation graph and no gradients will be calcualted.<br>
Also calling <code>.item()</code> will return a Python literal and would thus detach the result.<br>
This is the case in your <code>forward</code> method:</p>
<pre><code class="lang-python">binary_realisation = Tensor([model.forward(x).item(
        ) for model in self.classifiers_list[0:self.c_count]]).repeat(self.l_count+self.c_count, 1)
</code></pre>
<p><code>binary_realisation</code> will be a new tensor and thus Autograd will not backpropagate to <code>model</code> and any parameter in it.<br>
If that’s not desired, remove the <code>Tensor</code> usage as well as the <code>item()</code> operation and create a new tensor via <code>torch.stack</code> or <code>torch.cat</code>.</p>
<p>Also, Autograd won’t track any operations inside the <code>no_grad()</code> block, but I assume that’s intended.</p>

username: pklo16
cooked: <p>Thank you a lot for response!</p>
<p>Problem was hidden in exploding values during taking n-th power of Q, which made loss go to \infty.<br>
Nevertheless, your answers are very helpful since I had no clue it would mess with backprop. Thank once again!</p>