Weights don't update without using clone

Emre_Yalcinoglu: <p>I am trying to write a function to test different optimizers using Rosenbrock function. The following code works (at least for some optimizers), but I don’t understand why we need to clone <code>x</code> and why doesn’t it work without cloning.</p>
<pre><code class="lang-auto">def rosenbrock(x):
	return 100*(x[1]-x[0]**2)**2 + (1-x[0])**2


def optimize(x, optimizer, l):

	if not isinstance(optimizer, torch.optim.Optimizer):
		raise ValueError("You should pass an optimizer")
    
	# replaces the parameters of a given optimizer with x
	rosenbrock_test_params = torch.nn.Parameter(torch.tensor(x, dtype=torch.float, requires_grad=True))
	optimizer.param_groups[0]['params'] = [rosenbrock_test_params]

	positions = []

	while rosenbrock(x) &gt; l:
		# ! Why did we have to clone?
		x = optimizer.param_groups[0]['params'][0].clone() 
		y = rosenbrock(x)
        
		positions.append((x.detach().numpy().astype(np.float), y.detach().numpy().astype(np.float)))
        
		y.backward()
		optimizer.step()
		optimizer.zero_grad()

	if positions == []:
		print ("Parameter was already good enough")
		x = optimizer.param_groups[0]['params'][0]
		y = rosenbrock(x)
		positions.append((x.detach().numpy().astype(np.float), y.detach().numpy().astype(np.float)))
		return positions

	if math.isnan(positions[-1][1].item()):
		raise ValueError("Optimizer diverges")

	positions = np.array(positions, dtype=object)
	x_y, Z = positions[:,0], positions[:,1]
	X = np.array([i[0] for i in x_y])
	Y = np.array([i[1] for i in x_y])
    
	return X, Y, Z

lr = 0.0001
l = 4.5
x = (-1.5,1.5)

optimizer = torch.optim.SGD([torch.tensor([])], lr=lr, momentum=0.1, nesterov=True)
X, Y, Z = optimize(x, optimizer, l)
</code></pre>
<p>Any help would be appreciated!</p>

albanD: <p>Hi,</p>
<p>The structure of <code>param_group</code> is an implementation detail of the optimizer and the way you use it might work for some but not in general.<br>
The parameters should be passed when you initialize the optimizer as some optimizers do non-trivial work during their initialization with them.</p>

Emre_Yalcinoglu: <p>Thanks for the reply!</p>
<p>But then how can I create a function which takes an optimizer and some parameters as input?<br>
Let’s say in this example, I pass the optimizer with the parameter <code>x</code> already inside, but then how can I continue iterating over the parameters without accessing them via <code>param_groups</code>?</p>

albanD: <p>In this case, you won’t be able to pass an already created optimizer.<br>
You can pass the construction method though <code>optimize(x, optim.SGD, optim_args, l)</code></p>

Emre_Yalcinoglu: <p>Thank you, indeed passing <code>optim.SGD</code> or more simply, calling</p>
<pre><code class="lang-auto">x = torch.nn.Parameter(torch.tensor([-1.5,1.5], dtype=torch.float, requires_grad=True))
optimizer = torch.optim.SGD([x], lr=lr, momentum=0.1, nesterov=True)
</code></pre>
<p>and removing <code>.clone()</code>, instead of calling it with</p>
<pre><code class="lang-auto">x = (-1.5,1.5)
optimizer = torch.optim.SGD([torch.tensor([])], lr=lr, momentum=0.1, nesterov=True)
</code></pre>
<p>and setting the parameter manually, worked.</p>
<p>Even a more simple solution worked, which is removing <code>.clone()</code> and removing <code>rosenbrock_test_params</code> and directly setting the parameter with</p>
<pre><code class="lang-auto">optimizer.param_groups[0]['params'] = [torch.nn.Parameter(torch.tensor(x, dtype=torch.float, requires_grad=True))]
</code></pre>
<p>So, it looks like passing a reference is causing the need to clone. I don’t understand why though.<br>
Any idea about that, or do you think that it’s still an implementation detail depending on the optimizer?</p>

albanD: <blockquote>
<p>Any idea about that, or do you think that it’s still an implementation detail depending on the optimizer?</p>
</blockquote>
<p>It definitely is. Other optimizers will just plain error out if you try to add the parameters after they are initialized. So 100% implementation detail <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

Emre_Yalcinoglu: <p>I tried some built-in optimizers, and they work in both cases, or give an error in both cases. A lot of them seems to be working for this specific task.<br>
But I’d be happy if I can understand why we needed <code>clone()</code>, why passing a reference didn’t work. I tried to replicate this problem without using an optimizer but couldn’t.</p>

albanD: <p>I am not sure why the <code>.clone()</code> changes the behavior to be honest, You most likely will have to dive into the optimizer implementation to find out <img src="https://discuss.pytorch.org/images/emoji/apple/confused.png?v=9" title=":confused:" class="emoji" alt=":confused:"></p>