I’m a bit loss with your code
What is see is that you are assigning y  for example here
y = (x*(1-theta).expand_as(x)).add(z*theta.expand_as(z)) #use pytorch functions for math

Thus y is no longer pointing to the deepcopy you did but a inner variable in the scope.
x = y.sub(temp)

same there, you are reasigning x, thus, overwritting param group again.
You can wheter use in-place operators (in pytorch some functions has 2 versions w and w/o underscore, the second one is in-place.)
Example:
a=5 # a tensor
a.add(4) 
#a is still 5
a.add_(4)
#a is now 9

or just assign y like y.grad=whatever_you_want