Hi,
So pytorch is very different from tensorflow in the sense that your don’t create the graph once, and then just backprop through it.
The whole framework is built such that the graph is super cheat to build and so it is built on the fly.
That means that for every input for which you want to compute backprop, you should execute your computation with them, and then call backward on the output.
In your case, you should have:
import torch
import torch.nn as nn
from torch.autograd import Variable

dtype = torch.FloatTensor
class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        
        self.x_dim = 50
        self.hidden_size = 25
        # Parameters in modules have type Parameter
        self.w = nn.Parameter(torch.randn(self.x_dim, self.hidden_size).type(dtype))
        
        self.freeze_weights()
        
    def forward(self, x):
        return torch.mm(x, self.w)
    
    def freeze_weights(self):
        # There are no submodules to iterate through
        self.w.requires_grad = False

net = SimpleNet()
x = Variable(torch.randn(1, 25).type(dtype), requires_grad = True)

criterion = nn.MSELoss()
# The optimizer is given only x, so it will update only x, not the weights in net
# Set the learning rate to 1 so that the loss evolves quickly
optimizer = torch.optim.Adam([x], lr=1)

input = torch.randn(1, 50).type(dtype)
for i in range(50):
    # You should only package your inputs inside the loop
    input_var = Variable(input)
    # Compute the forward pass here
    t = net(input_var)
    loss = criterion(x, t)
    print("Loss after {}\t steps is {}".format(i, loss.data[0]))
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()