鱼C论坛

 找回密码
 立即注册
查看: 507|回复: 9

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

[复制链接]
发表于 2024-4-2 16:48:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
以下是我的代码,为什么我的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[i,:]-geom[j,:]
                                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[keys[-1]])
                        last_w = copy.deepcopy(params[keys[-2]])
                        #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=[0,0.8],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([NAtom*3, NAtom*3])
        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()

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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[i,:]-geom[j,:]
                                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[keys[-1]])
                        last_w = copy.deepcopy(params[keys[-2]])
                        #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=[0,0.8],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([NAtom*3, NAtom*3])
        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()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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[keys])
        last_w = copy.deepcopy(params[keys])
        
        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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-3 10:03:42 | 显示全部楼层
FishC 发表于 2024-4-3 09:57
问题在于在`train`函数中的循环中,你使用了`gen_tensor = input_tensor`,这导致在每次迭代中都使用相 ...

我就是这样修改的,但是punish还是没有变化
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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[i] - geom[j]
            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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

这个punishment跟我的代码没有区别
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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[i] - geom[j]
            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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

不能得到正确的结果
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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[i] - geom[j]
            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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-15 13:01

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表