lqhenwunai 发表于 2024-3-25 08:54:44

神经网络训练惩罚函数问题

用pytorch随机生成一个张量,并用Calc_bond_length函数作为惩罚函数,然后进行神经网络训练。但是以下代码不能实现目的,所打印的input tensor在循环中没有变化。试了几种不同的网络结构,input tenso在循环中都没有变化。问题在哪里?def Calc_bond_length(geom,thresh1,thresh2):
        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)

        dist_max = np.max(bond_length)
        dist_min = np.min(bond_length)

        if dist_max > thresh2 or dist_min < thresh1:
                return ConvertTensor(9,True)
        else:
                return ConvertTensor(0,True)


        def train(self,thresh1,thresh2,maxit=1000):

                for i in range(maxit):
                        self.optimizer.zero_grad()
                        input_tensor = self.RandomInput        
                        print(input_tensor)

                        gen_tensor   = self.forward(input_tensor)
       
                        punish = 0
                        punish = Calc_bond_length(gen_tensor,thresh1,thresh2)       
               

                        loss    = punish
               
                        self.info.counter += 1
                        if self.info.counter%10==0:
                                self.info.progress.append(loss.item())
       
       
                        loss.backward()
                        self.optimizer.step()

                        if loss.item()<2:
                                print("break")
                                break


                return loss,gen_tensor

FishC 发表于 2024-3-25 08:54:59

在你的代码中,循环中的`gen_tensor`是神经网络的输出,而`input_tensor`是随机生成的张量,并没有在循环中变化。这就是为什么打印出来的`input_tensor`没有变化的原因。

如果想要在每次循环中改变输入张量,可以将生成随机张量的代码放在循环内部。另外,别忘了在循环开始之前调用`self.optimizer.zero_grad()`来清除梯度。

下面是修改后的代码:
def train(self, thresh1, thresh2, maxit=1000):
    for i in range(maxit):
      self.optimizer.zero_grad()
      
      input_tensor = self.RandomInput()
      gen_tensor = self.forward(input_tensor)
      
      punish = Calc_bond_length(gen_tensor, thresh1, thresh2)
      
      loss = punish
      
      self.info.counter += 1
      if self.info.counter % 10 == 0:
            self.info.progress.append(loss.item())
   
      loss.backward()
      self.optimizer.step()
      
      if loss.item() ...

希望对你有所帮助!

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

lqhenwunai 发表于 2024-3-25 09:01:16

FishC 发表于 2024-3-25 08:54
在你的代码中,循环中的`gen_tensor`是神经网络的输出,而`input_tensor`是随机生成的张量,并没有在循环中 ...

哦,我说错了,是gen_tensor在循环中不发生改变。

FishC 发表于 2024-3-25 09:01:26

lqhenwunai 发表于 2024-03-25 09:01
哦,我说错了,是gen_tensor在循环中不发生改变。

如果`gen_tensor`在循环中没有变化,可能是因为你没有使用梯度下降优化算法来更新神经网络的参数。在训练步骤中,你需要计算损失函数并调用`backward()`方法计算梯度,然后调用优化器的`step()`方法来更新参数。请确保你的代码中包含了这些步骤。

在你的代码中,我看不到你定义的优化器。你需要在模型的初始化函数中创建一个优化器,例如使用随机梯度下降优化算法(SGD):

self.optimizer = torch.optim.SGD(self.parameters(), lr=0.01)

另外,请确保在每次循环中都调用`self.optimizer.zero_grad()`来清除梯度。

最后,检查一下训练循环中的损失函数计算是否正确,并确认`Calc_bond_length`函数返回的`punish`张量是可微分的(即可以进行反向传播)。

如果你的代码已经包含了这些步骤,但仍然没有更新`gen_tensor`,那可能是模型架构或数据流的问题。你可以检查模型的前向传播是否正确,以及数据输入是否正确传递给了模型。

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

lqhenwunai 发表于 2024-3-25 09:04:25

FishC 发表于 2024-3-25 09:01
如果`gen_tensor`在循环中没有变化,可能是因为你没有使用梯度下降优化算法来更新神经网络的参数。在训 ...

下面是我的网络类定义。不知道有没有什么问题。
另外怎么查看网络参数有没有更新?
class Generator(nn.Module):
        """ Architecture of the Generator, uses res-blocks """

        def __init__(self,para):
                super().__init__()
               
                self.info = para
                self.info.counter = 0
                self.info.progress = []

                self.model= self.G_model()
                self.optimizer = para.optimizer(self.parameters(),lr=para.lr)
                self.flag_network = para.Gflag_network # =1, use network, =2 not use network       

                self.RandomInput= self.Gen_Random_input()
                #self.model.apply(weight_init)
                print("Generator model")
                print(self.model)

        ##################################################3
        def G_model(self):
                info       = self.info

                model_flag = info.model_flag
                Nlayer   = info.Nlayer
                NAtom      = info.NAtom
                increment= info.increment
                activation_func = info.activation_func
                inp_dim         = NAtom*3
        #-----------------------------------------------
        #----------------------------------------------
                if model_flag==2:#increase then decrease
                        module_list=[]
                        for i in range(Nlayer):
                                module_list.append(nn.Linear(inp_dim,inp_dim+increment))
                                module_list.append(activation_func)
                                inp_dim+=increment
       
                        for i in range(Nlayer):
                                module_list.append(nn.Linear(inp_dim,inp_dim-increment))
                                module_list.append(activation_func)
                                inp_dim-=increment

                        module_list.append(nn.Linear(inp_dim,inp_dim))       
                        model = nn.Sequential(*module_list)
        #-----------------------------------------------------


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


        def forward(self,input_tensor,flag=1):

                #use random input
                if flag==1:
                        out=self.model(input_tensor)
               
                if flag==2: #not use any network
                        out = input_tensor
               
                return out


        def Gen_Random_input(self):
                NAtom = self.info.NAtom
                mean= self.info.configs.mean
                std   = self.info.configs.std
                inp   = torch.randn(NAtom*3)
                input_tensor = inp*std + mean
                input_tensor.requires_grad_(True)       
                return input_tensor
       
        def train(self,thresh1,thresh2,maxit=1000):

                for i in range(maxit):
                        self.optimizer.zero_grad()
                        input_tensor = self.RandomInput        
                        print(input_tensor)

                        gen_tensor   = self.forward(input_tensor, self.flag_network)
       
                        punish = 0
                        punish = Calc_bond_length(gen_tensor,thresh1,thresh2)       
               
        #                targets = torch.ones_like(gen_tensor)
        #                loss    = self.info.loss_func(gen_tensor,targets)+punish
                        loss    = punish
               
                        self.info.counter += 1
                        if self.info.counter%10==0:
                                self.info.progress.append(loss.item())
       
       
                        loss.backward()
                        self.optimizer.step()

                        if loss.item()<2:
                                print("break")
                                break


                return loss,gen_tensor

FishC 发表于 2024-3-25 09:05:02

lqhenwunai 发表于 2024-03-25 09:04
下面是我的网络类定义。不知道有没有什么问题。
另外 ...

在你的代码中,定义了一个`Generator`类作为神经网络模型。看起来你的模型定义是正确的,但有几个问题需要注意:

1. 在`G_model`函数中,你创建了一个`module_list`变量,并将线性层和激活函数按顺序添加到其中。然而,在增加层之后,你忘记对应的循环结构中有两个缩进错误,导致这些层不会与主模块列表一起添加。你需要将这两个循环的缩进位置调整到与前面的循环相同。

2. 在`forward`函数中,你在使用随机输入时有一个小错误。条件`if flag==1`下的代码块应该位于此之后,而不是包含在其中。你需要将`out = self.model(input_tensor)`和`return out`移动到适当的位置。

3. 关于如何检查网络参数是否已更新,你可以使用`state_dict()`方法打印模型的参数字典。该方法返回一个Python字典对象,其中包含模型的所有参数及其对应的张量值。你可以在训练循环中适当的位置调用`print(self.state_dict())`来查看模型参数是否发生变化。

修正后的代码如下所示(已标注修复部分):

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

    def __init__(self, para):
      super().__init__()
      self.info = para
      self.info.counter = 0
      self.info.progress = []

      self.model = self.G_model()
      self.optimizer = para.optimizer(self.parameters(), lr=para.lr)
      self.flag_network = para.Gflag_network# =1, use network, =2 not use network
      self.RandomInput = self.Gen_Random_input()

      print("Generator model")
      print(self.model)

    def G_model(self):
      info = self.info
      model_flag = info.model_flag
      Nlayer = info.Nlayer
      NAtom = info.NAtom
      increment = info.increment
      activation_func = info.activation_func
      inp_dim = NAtom * 3

      module_list = []# Fixed: Initialize an empty list outside the loop

      if model_flag == 2:# increase then decrease
            for i in range(Nlayer):
                module_list.append(nn.Linear(inp_dim, inp_dim + increment))
                module_list.append(activation_func)
                inp_dim += increment

            for i in range(Nlayer):# Fixed: Correct indentation
                module_list.append(nn.Linear(inp_dim, inp_dim - increment))
                module_list.append(activation_func)
                inp_dim -= increment

      module_list.append(nn.Linear(inp_dim, inp_dim))

      model = nn.Sequential(*module_list)
      return model

    def forward(self, input_tensor, flag=1):
      if flag == 1:
            out = self.model(input_tensor)# Moved from "if flag==1" condition
      elif flag == 2:
            out = input_tensor

      return out

    def Gen_Random_input(self):
      NAtom = self.info.NAtom
      mean = self.info.configs.mean
      std = self.info.configs.std
      inp = torch.randn(NAtom * 3)
      input_tensor = inp * std + mean
      input_tensor.requires_grad_(True)
      return input_tensor

    def train(self, thresh1, thresh2, maxit=1000):
      for i in range(maxit):
            self.optimizer.zero_grad()
            input_tensor = self.RandomInput
            print(input_tensor)
            gen_tensor = self.forward(input_tensor, self.flag_network)

            punish = Calc_bond_length(gen_tensor, thresh1, thresh2)
            loss = punish

            self.info.counter += 1
            if self.info.counter % 10 == 0:
                self.info.progress.append(loss.item())

            loss.backward()
            self.optimizer.step()

            # Check if the model parameters have been updated
            print(self.state_dict())

            if loss.item():
                ...

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 神经网络训练惩罚函数问题