lqhenwunai 发表于 2024-4-2 16:48:32

为什么我的惩罚函数没有变化

以下是我的代码,为什么我的punish以及init_weight等函数在循环中没有变化?import torch
import torch.nn as nn
import torch.nn.functional as f
from torch.autograd import Variable
import numpy as np
import os
import copy
import random
import pandas
import matplotlib.pyplot as plt
from torch.autograd import Function
def ConvertTensor(vec,grad_flag=True):
        return torch.tensor(vec,dtype=torch.float32,requires_grad=grad_flag)


def Punishment(geom,generator,flag=1):
        if flag==1:
                thresh1 = generator.thresh1 #smaller
                thresh2 = generator.thresh2 #larger
                w1      = generator.w1
                w2      = generator.w2
       
                ThreeN = len(geom)
                NAtom= int(ThreeN/3)
                geom = geom.view(NAtom,3)
                bond_length=[]
                for i in range(NAtom):
                        for j in range(i+1,NAtom):
                                diff = geom-geom
                                diff = torch.linalg.norm(diff)
                                bond_length.append(diff)
       
                bond_length = ConvertTensor(bond_length)
                dist_max = torch.max(bond_length)
                dist_min = torch.min(bond_length)
                #if all bond lengths are good
                res1 = 0
                res2 = 0
                #if any bond is too short or too long
                if dist_min < thresh1:
                        res1 = -(dist_min - thresh1)
                if dist_max > thresh2:
                        res2 =dist_max - thresh2
       
                return w1*res1 + w2*res2


class Generator(nn.Module):
        """ Architecture of the Generator, uses res-blocks """

        def __init__(self):
                super().__init__()
               
                self.counter = 0
                self.progress = []
                self.NAtom = 12
                self.model= self.G_model()
                self.optimizer = torch.optim.Adam(self.parameters(),lr=0.001)

                self.thresh1 = 1.6
                self.thresh2 = 12.6
                #---------------------------------------------
                #the below are used for punishment function
                #for flag 1
                self.RandomInput= self.Gen_Random_input()

       
                #--------------------------------------------
                #self.model.apply(weight_init)
                print("Generator model")
                print(self.model)

        ###################################################
        def G_model(self):
                NAtom         = self.NAtom
                activation_func = nn.Sigmoid()
                inp_dim         = NAtom*3
                Normalizer      = nn.LayerNorm
                model_flag      =1
        #-----------------------------------------------
                if model_flag ==1: #simple
                        model = nn.Sequential(
                                 nn.Linear(inp_dim, inp_dim),
                                        activation_func
                )

                if model_flag ==101: #simple
                        model = nn.Sequential(
                                 nn.Linear(inp_dim, inp_dim),
                                        activation_func,
                                               Normalizer(inp_dim)
                )

                return model
        #-----------------------------------------------
        #######################################################


        def forward(self,input_tensor,weight,bias=0):

                out=self.model(input_tensor)
                out=torch.matmul(out,weight)+bias
                out=out+bias
                return out


        def Gen_Random_input(self):
                NAtom = self.NAtom
                mean= 0
                std   = 2
                inp   = torch.randn(NAtom*3)
                input_tensor = inp*std + mean
                input_tensor.requires_grad_(True)       
                return input_tensor
       
        def train(self,target_flag,maxit=1000):

                thresh1 = self.thresh1
                thresh2 = self.thresh2
                input_tensor = self.Gen_Random_input()
                init_bias = torch.zeros_like(input_tensor)
                init_weight = torch.ones(self.NAtom*3,self.NAtom*3)       
                self.w1=1
                self.w2=1

                for i in range(maxit):
               
                        #generate fake data       
                        gen_tensor   = self.forward(input_tensor,init_weight,init_bias)
                        self.gen_tensor = gen_tensor
                        #calculate the punishment of the fake data
                        punish= Punishment(gen_tensor.detach(),self,flag=1)       
                        print(punish)       
                        #punish= torch.max(punish,torch.zeros_like(punish))

                        loss   = punish


                        #get the network parameters
                        params = self.state_dict()
                        keys = list(params.keys())
                        last_b = copy.deepcopy(params])
                        last_w = copy.deepcopy(params])
                        #do some check
                        assert len(last_b) == self.NAtom*3,        print("error length of last_b not equal to threeN, len(keys)=",len(last_b))
                        assert len(last_w) == self.NAtom*3,    print("error length of last_w not equal to threeN, len(keys)=",len(last_b))

                        #update the init_bias and init_weight
                        init_bias = ConvertTensor(last_b,True)
                        init_weight = ConvertTensor(last_w,True)       

                        #run the backward training
                        self.optimizer.zero_grad()
                        loss.backward()
                        self.optimizer.step()

                        if punish > 10:
                                init_weight = torch.zeros_like(init_weight)

                        #plot stuff
                        self.counter += 1
                        if self.counter%10==0:
                                self.progress.append(loss.item())
                #                print(gen_tensor)


                return loss,gen_tensor


        def plot_progress(self):
                df = pandas.DataFrame(self.progress,columns=['loss'])
#                df.plot(ylim=,marker='.',grid=True,title="generator_loss" )
                df.plot(marker='.',grid=True,title="generator_loss" )
#                plt.savefig("generator_loss.png")
                plt.show()



#-----


if __name__=="__main__":

        generator = Generator()
        NAtom=12
        init_weight = torch.ones()
        geom = generator.forward(generator.RandomInput,weight=init_weight)       
        maxit=500
        print("max iteration=",maxit)
        loss,gen_tensor = generator.train(target_flag=1,maxit=maxit)
       
        generator.plot_progress()

FishC 发表于 2024-4-2 16:48:45

问题出在以下几个地方:
1. 在你的`Punishment`函数中,你没有传入`generator`对象。所以在使用`generator.thresh1`和`generator.w1`等属性时会报错。你需要修改为`Punishment(geom,generator,flag=1)`。
2. 在你的`forward`函数中,你传入了`weight`参数,但是在调用`self.model`时并没有使用它。你可以尝试修改为`out = self.model(input_tensor) + torch.matmul(weight, input_tensor)`。
3. 在你的`Gen_Random_input`函数中,你没有将输入的`grad_flag`传递给`torch.randn()`方法。你需要修改为`inp = torch.randn(NAtom*3, dtype=torch.float32, requires_grad=True)`。
4. 在你的`train`函数中,在循环开始之前,你需要先调用`self.optimizer.zero_grad()`来清空之前计算的梯度。

以上是我发现的问题和建议修复的地方,你可以尝试将代码改进后再运行一下看看是否有更好的结果。希望能对你有所帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2024-4-3 09:57:19

FishC 发表于 2024-4-2 16:48
问题出在以下几个地方:
1. 在你的`Punishment`函数中,你没有传入`generator`对象。所以在使用`generator ...

下面是我现在修改后的代码,但是punish在循环过程中还是没有变化。问题在哪里?
import torch
import torch.nn as nn
import torch.nn.functional as f
from torch.autograd import Variable
import numpy as np
import os
import copy
import random
import pandas
import matplotlib.pyplot as plt
from torch.autograd import Function
def ConvertTensor(vec,grad_flag=True):
        return torch.tensor(vec,dtype=torch.float32,requires_grad=grad_flag)

class Generator(nn.Module):
        """ Architecture of the Generator, uses res-blocks """

        def __init__(self):
                super().__init__()
               
                self.counter = 0
                self.progress = []
                self.NAtom = 12
                self.model= self.G_model()
                self.optimizer = torch.optim.Adam(self.parameters(),lr=0.001)
                self.loss_func = nn.MSELoss()

                self.thresh1 = 1.6
                self.thresh2 = 12.6
                #---------------------------------------------
                #the below are used for punishment function
                #for flag 1
                self.RandomInput= self.Gen_Random_input()

       
                #--------------------------------------------
                #self.model.apply(weight_init)
                print("Generator model")
                print(self.model)

        ###################################################
        def G_model(self):
                NAtom         = self.NAtom
                activation_func = nn.ReLU()
                inp_dim         = NAtom*3
                Normalizer      = nn.LayerNorm
                model_flag      =1
        #-----------------------------------------------
                if model_flag ==1: #simple
                        model = nn.Sequential(
                                 nn.Linear(inp_dim, inp_dim),
                                        activation_func,
                                 nn.Linear(inp_dim, inp_dim),
                                        activation_func


                )

                if model_flag ==101: #simple
                        model = nn.Sequential(
                                 nn.Linear(inp_dim, inp_dim),
                                        activation_func,
                                               Normalizer(inp_dim)
                )

                return model
        #-----------------------------------------------
        #######################################################


        def forward(self,input_tensor,weight,bias=0):
                out=self.model(input_tensor)
                out=torch.matmul(out,weight)+bias
                out=out+bias

                return out


        def Punishment(self,geom):
                thresh1 = self.thresh1 #smaller
                thresh2 = self.thresh2 #larger
                w1      = self.w1
                w2      = self.w2
               
                ThreeN = len(geom)
                NAtom= int(ThreeN/3)
                geom = geom.view(NAtom,3)
                bond_length=[]
                for i in range(NAtom):
                        for j in range(i+1,NAtom):
                                diff = geom-geom
                                diff = torch.linalg.norm(diff)
                                bond_length.append(diff)
               
                bond_length = ConvertTensor(bond_length)
                dist_max = torch.max(bond_length)
                dist_min = torch.min(bond_length)
                #if all bond lengths are good
                res1 = 0
                res2 = 0
                #if any bond is too short or too long
                if dist_min < thresh1:
                        res1 = -(dist_min - thresh1)
                if dist_max > thresh2:
                        res2 =dist_max - thresh2
               
                return w1*res1 + w2*res2
       


        def Gen_Random_input(self):
                NAtom = self.NAtom
                mean= 0
                std   = 2
                inp   = torch.randn(NAtom*3)
                input_tensor = inp*std + mean
                input_tensor.requires_grad_(True)       
                return input_tensor
       
        def train(self,target_flag,maxit=1000):

                thresh1 = self.thresh1
                thresh2 = self.thresh2
                input_tensor = self.Gen_Random_input()
                init_bias = torch.zeros_like(input_tensor)
                init_weight = torch.ones(self.NAtom*3,self.NAtom*3)       
                self.w1=1
                self.w2=1

                gen_tensor = input_tensor
                for i in range(maxit):
                        self.optimizer.zero_grad()
                        #generate fake data       
                        gen_tensor   = self.forward(gen_tensor,init_weight,init_bias)
                        self.gen_tensor = gen_tensor
                        #calculate the punishment of the fake data
                        punish= self.Punishment(gen_tensor.detach())       
                #        print(gen_tensor)       
                        print(punish)       
                        #punish= torch.max(punish,torch.zeros_like(punish))
                        loss   = self.loss_func(punish,torch.zeros_like(punish))


                        #get the network parameters
                        params = self.state_dict()
                        keys = list(params.keys())
                        last_b = copy.deepcopy(params])
                        last_w = copy.deepcopy(params])
                        #do some check
                        assert len(last_b) == self.NAtom*3,        print("error length of last_b not equal to threeN, len(keys)=",len(last_b))
                        assert len(last_w) == self.NAtom*3,    print("error length of last_w not equal to threeN, len(keys)=",len(last_b))

                        #update the init_bias and init_weight
                        init_bias = ConvertTensor(last_b,True)
                        init_weight = ConvertTensor(last_w,True)       

                        #run the backward training
                        loss.backward()
                        self.optimizer.step()

                        #plot stuff
                        self.counter += 1
                        if self.counter%10==0:
                                self.progress.append(loss.item())
                #                print(gen_tensor)


                return loss,gen_tensor


        def plot_progress(self):
                df = pandas.DataFrame(self.progress,columns=['loss'])
#                df.plot(ylim=,marker='.',grid=True,title="generator_loss" )
                df.plot(marker='.',grid=True,title="generator_loss" )
#                plt.savefig("generator_loss.png")
                plt.show()



#-----


if __name__=="__main__":

        generator = Generator()
        NAtom=12
        init_weight = torch.ones()
        geom = generator.forward(generator.RandomInput,weight=init_weight)       
        maxit=500
        print("max iteration=",maxit)
        loss,gen_tensor = generator.train(target_flag=1,maxit=maxit)
       
        generator.plot_progress()

FishC 发表于 2024-4-3 09:57:39

lqhenwunai 发表于 2024-04-03 09:57
下面是我现在修改后的代码,但是punish在循环过程中还 ...

问题在于在`train`函数中的循环中,你使用了`gen_tensor = input_tensor`,这导致在每次迭代中都使用相同的输入作为生成器的输入。因此,生成器的输出`gen_tensor`没有改变,所以惩罚函数`Punishment`的结果也不会改变。

你可以尝试将其修改为`gen_tensor = self.forward(gen_tensor, init_weight, init_bias)`,以便用上一次迭代的生成器输出作为下一次迭代的输入。这样,生成器的输出将随着迭代次数的增加而逐渐改变,从而使惩罚函数的结果也能够变化。

另外,你还需要将`punish`的计算方式修改为`loss = self.loss_func(punish, torch.zeros_like(punish))`,并且在每次迭代前调用`self.optimizer.zero_grad()`来清空之前的梯度计算。

修改后的代码如下:

def train(self, target_flag, maxit=1000):
    thresh1 = self.thresh1
    thresh2 = self.thresh2
    input_tensor = self.Gen_Random_input()
    init_bias = torch.zeros_like(input_tensor)
    init_weight = torch.ones(self.NAtom*3, self.NAtom*3)
   
    self.w1 = 1
    self.w2 = 1
   
    gen_tensor = input_tensor
   
    for i in range(maxit):
      self.optimizer.zero_grad()
      
      # 生成假数据
      gen_tensor = self.forward(gen_tensor, init_weight, init_bias)
      self.gen_tensor = gen_tensor
      
      # 计算惩罚值
      punish = self.Punishment(gen_tensor.detach())
      print(punish)
      
      loss = self.loss_func(punish, torch.zeros_like(punish))
      
      params = self.state_dict()
      keys = list(params.keys())
      last_b = copy.deepcopy(params)
      last_w = copy.deepcopy(params)
      
      assert len(last_b) == self.NAtom*3, print("error length of last_b not equal to threeN, len(keys)=", len(last_b))
      assert len(last_w) == self.NAtom*3, print("error length of last_w not equal to threeN, len(keys)=", len(last_b))
      
      init_bias = ConvertTensor(last_b, True)
      init_weight = ConvertTensor(last_w, True)
      
      loss.backward()
      self.optimizer.step()
      
      self.counter += 1
      if self.counter % 10 == 0:
            self.progress.append(loss.item())
   
    return loss, gen_tensor

希望这次的修改能够解决你的问题!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2024-4-3 10:03:42

FishC 发表于 2024-4-3 09:57
问题在于在`train`函数中的循环中,你使用了`gen_tensor = input_tensor`,这导致在每次迭代中都使用相 ...

我就是这样修改的,但是punish还是没有变化

FishC 发表于 2024-4-3 10:03:57

lqhenwunai 发表于 2024-04-03 10:03
我就是这样修改的,但是punish还是没有变化

抱歉,我在之前的回答中犯了错误。问题出在`Punishment`函数中。你在计算`bond_length`时,应该是对每一对原子计算差异,而不是对整个几何体进行计算。另外,在计算`diff`时,你需要使用索引来获取每对原子的坐标差异。以下是修改后的代码:

def Punishment(self, geom):
    thresh1 = self.thresh1 #smaller
    thresh2 = self.thresh2 #larger
    w1      = self.w1
    w2      = self.w2
   
    ThreeN = len(geom)
    NAtom= int(ThreeN/3)
    geom = geom.view(NAtom,3)
   
    bond_length = []
    for i in range(NAtom):
      for j in range(i+1,NAtom):
            diff = geom - geom
            diff = torch.linalg.norm(diff)
            bond_length.append(diff)
   
    bond_length = ConvertTensor(bond_length)
    dist_max = torch.max(bond_length)
    dist_min = torch.min(bond_length)
   
    res1 = 0
    res2 = 0
   
    if dist_min < thresh1:
      res1 = -(dist_min - thresh1)
    if dist_max > thresh2:
      res2 = dist_max - thresh2
      
    return w1*res1 + w2*res2

请尝试运行修改后的代码,看看是否能够得到正确的惩罚结果。抱歉给你带来了困扰!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2024-4-3 10:06:00

FishC 发表于 2024-4-3 10:03
抱歉,我在之前的回答中犯了错误。问题出在`Punishment`函数中。你在计算`bond_length`时,应该是对每 ...

这个punishment跟我的代码没有区别

FishC 发表于 2024-4-3 10:06:14

lqhenwunai 发表于 2024-04-03 10:06
这个punishment跟我的代码没有区别

非常抱歉,我之前的回答仍然存在错误。在`Punishment`函数中,你需要计算每对原子之间的距离,并将其与阈值进行比较,以计算惩罚。以下是修改后的代码示例:

def Punishment(geom, generator):
    thresh1 = generator.thresh1
    thresh2 = generator.thresh2
    w1 = generator.w1
    w2 = generator.w2
   
    ThreeN = len(geom)
    NAtom = int(ThreeN/3)
    geom = geom.view(NAtom, 3)
   
    res1 = 0
    res2 = 0

    for i in range(NAtom):
      for j in range(i+1, NAtom):
            diff = geom - geom
            bond_length = torch.linalg.norm(diff)

            if bond_length < thresh1:
                res1 += -(bond_length - thresh1)
            
            if bond_length > thresh2:
                res2 += bond_length - thresh2
   
    return w1 * res1 + w2 * res2

请尝试使用修改后的`Punishment`函数,看看是否能够得到正确的惩罚结果。非常抱歉之前给你带来的困惑!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2024-4-3 10:07:18

FishC 发表于 2024-4-3 10:06
非常抱歉,我之前的回答仍然存在错误。在`Punishment`函数中,你需要计算每对原子之间的距离,并将其与 ...

不能得到正确的结果

FishC 发表于 2024-4-3 10:07:34

lqhenwunai 发表于 2024-04-03 10:07
不能得到正确的结果

非常抱歉,我之前回答中的代码仍然有问题。在Punishment函数中,你使用了一个列表来存储每对原子之间的距离,但是你没有正确计算每对原子之间的距离,而是直接将整个geom张量减去自身,这是错误的。以下是修复后的代码示例:

def Punishment(geom, generator):
    thresh1 = generator.thresh1
    thresh2 = generator.thresh2
    w1 = generator.w1
    w2 = generator.w2

    ThreeN = len(geom)
    NAtom = int(ThreeN/3)
    geom = geom.view(NAtom, 3)

    bond_length = []
    for i in range(NAtom):
      for j in range(i+1, NAtom):
            diff = geom - geom
            diff = torch.linalg.norm(diff)
            bond_length.append(diff)

    bond_length = torch.tensor(bond_length)
    dist_max = torch.max(bond_length)
    dist_min = torch.min(bond_length)

    res1 = 0
    res2 = 0

    if dist_min < thresh1:
      res1 = -(dist_min - thresh1)
    if dist_max > thresh2:
      res2 = dist_max - thresh2

    return w1 * res1 + w2 * res2

请尝试使用修复后的`Punishment`函数,看看是否能够得到正确的惩罚结果。非常抱歉之前给你带来的困惑!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 为什么我的惩罚函数没有变化