lqhenwunai 发表于 2023-11-28 22:47:02

神经网络自定义损失函数问题求助

求教各位大佬,

我想自定义一个损失函数,伪码的话

Y=model(X) #由网络训练得到Y

def myloss():
       
        loss = nn.MSELoss( f(Y),ref)#ref是某个参考矩阵,判断Y的f变换后与ref 的差
        loss.requires_grad_(True)

        return loss

请问这样写正确么?

我在训练的时候打印loss
Epoch0 loss0.47606658935546875
Epoch50 loss0.47606658935546875
Epoch100 loss0.47606658935546875
Epoch150 loss0.47606658935546875
Epoch200 loss0.47606658935546875
Epoch250 loss0.47606658935546875
Epoch300 loss0.47606658935546875
Epoch350 loss0.47606658935546875
Epoch400 loss0.47606658935546875
Epoch450 loss0.47606658935546875

loss值都没有变化。虽然Y是有变化的,但是f(Y)是没有变化的。我觉得是由于backward没有正确反向传播回去。但我不知道这个想法对不对,也不知道怎么修改。谢谢各位大佬帮助。               

FishC_GPT 发表于 2023-11-28 22:47:21

你的自定义损失函数的写法基本正确,但是在损失函数中使用`nn.MSELoss`可能会导致梯度无法正确传播。为了解决这个问题,你可以使用`torch.autograd.Function`创建一个自定义的损失函数。

以下是一个示例代码,其中定义了一个自定义的损失函数`MyLoss`,它计算Y和ref之间的差,并通过`backward()`方法实现梯度的传播:

import torch
from torch.autograd import Function

class MyLoss(Function):
    @staticmethod
    def forward(ctx, Y, ref):
      ctx.save_for_backward(Y, ref)
      loss = (Y - ref).pow(2).sum()# 自定义损失函数的计算方式
      return loss

    @staticmethod
    def backward(ctx, grad_output):
      Y, ref = ctx.saved_tensors
      grad_Y = 2 * (Y - ref)# 损失函数对Y的梯度计算
      grad_ref = None# 如果ref需要求梯度,可以在此处计算

      return grad_Y, grad_ref

# 在训练过程中使用自定义损失函数
loss_fn = MyLoss()

# 在每个iteration中使用自定义损失函数进行前向传播和反向传播
Y = model(X)
loss = loss_fn(Y, ref)
loss.backward()

你可以根据自己的需求修改`MyLoss`类中的`forward()`方法和`backward()`方法来计算自定义损失函数的值和梯度。这样,你就可以在训练过程中使用刚刚定义的自定义损失函数了。希望对你有帮助!

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 08:31:56

FishC_GPT 发表于 2023-11-28 22:47
你的自定义损失函数的写法基本正确,但是在损失函数中使用`nn.MSELoss`可能会导致梯度无法正确传播。为了解 ...

谢谢大佬,我试一下。再拜{:5_111:}

FishC_GPT 发表于 2023-11-29 08:32:11

lqhenwunai 发表于 2023-11-29 08:31
谢谢大佬,我试一下。再拜{:5_111:}

不客气,祝你好运!有任何问题都可以随时向我提问。祝你编程愉快!

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 10:09:58

FishC_GPT 发表于 2023-11-28 22:47
你的自定义损失函数的写法基本正确,但是在损失函数中使用`nn.MSELoss`可能会导致梯度无法正确传播。为了解 ...

不好意思继续麻烦大佬,

我现在通过autograd定义了损失函数:
class MyLoss(Function):
    @staticmethod
    def forward(ctx,Y,ref):
      ctx.save_for_backward(Y, ref)
      loss = (Y-ref).pow(2).sum()
      return loss
    @staticmethod
    def backward(ctx,grad_output):
      Y,ref = ctx.saved_tensors
      grad_Y = 2 * (Y - ref)
      grad_ref = None
      return grad_Y, grad_ref

然后在我的网络中这样调用:
    def train(self):
      gen_geom= self.forward()# 通过网络生成Y, Y=model(X)
      self.optimiser.zero_grad()
      #gen_CTable = f (gen_geom), 即得到f(Y)
      gen_CTable = torch.tensor(Tensor_Connectivity(self.NAtom, gen_geom),dtype=torch.float32)
      gen_CTable = gen_CTable.view(1,self.NAtom*self.NAtom)
      loss            = MyLoss.apply(gen_CTable,self.ref_CTable_T)
      loss.requires_grad_(True)
      

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

      loss.backward()
      self.optimiser.step()
      return loss

但是还是出现之前的问题,即loss没有变化:
Epoch0 loss1830.0
Epoch50 loss1830.0
Epoch100 loss1830.0
Epoch150 loss1830.0
Epoch200 loss1830.0
Epoch250 loss1830.0
Epoch300 loss1830.0
Epoch350 loss1830.0
Epoch400 loss1830.0
Epoch450 loss1830.0
Epoch500 loss1830.0
Epoch550 loss1830.0
Epoch600 loss1830.0
Epoch650 loss1830.0
Epoch700 loss1830.0
Epoch750 loss1830.0
Epoch800 loss1830.0
Epoch850 loss1830.0
Epoch900 loss1830.0
Epoch950 loss1830.0

FishC_GPT 发表于 2023-11-29 10:10:10

lqhenwunai 发表于 2023-11-29 10:09
不好意思继续麻烦大佬,

我现在通过autograd定义了 ...

你的损失函数实现看起来是正确的。我注意到你在损失函数计算中使用了`sum()`方法,这会将所有元素相加得到一个标量,可能导致梯度消失。你可以尝试改用`mean()`方法来计算平均损失。请尝试以下修改:class MyLoss(Function):    @staticmethod    def forward(ctx, Y, ref):      ctx.save_for_backward(Y, ref)      loss = (Y - ref).pow(2).mean()# 将sum()改为mean()      return loss    @staticmethod    def backward(ctx, grad_output):      Y, ref = ctx.saved_tensors      n = Y.shape# 样本数量      grad_Y = 2 * (Y - ref) / n# 损失函数对Y的梯度计算,并除以样本数量      grad_ref = None      return grad_Y, grad_ref另外,在调用自定义损失函数时,你不需要再手动将`loss`设置为`requires_grad_(True)`,因为它已经在损失函数的`forward()`方法中被定义为需要梯度。我希望这些修改能够解决问题,让损失函数能够正常更新。如果还有问题,请随时继续提问。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 10:20:13

FishC_GPT 发表于 2023-11-29 10:10
你的损失函数实现看起来是正确的。我注意到你在损失函数计算中使用了`sum()`方法,这会将所有元素相加得 ...

将sum改成mean之后还是存在一样的问题。loss函数没有变化
Epoch0 loss0.47606658935546875
Epoch50 loss0.47606658935546875
Epoch100 loss0.47606658935546875
Epoch150 loss0.47606658935546875
Epoch200 loss0.47606658935546875
Epoch250 loss0.47606658935546875
Epoch300 loss0.47606658935546875
Epoch350 loss0.47606658935546875

另外,loss.requires_grad_(True)似乎是必须的,如果我把它注释掉,会报错说
element 0 of tensors does not require grad and does not have a grad_fn

不知道这个报错信息是否能有什么帮助。

FishC_GPT 发表于 2023-11-29 10:20:24

lqhenwunai 发表于 2023-11-29 10:20
将sum改成mean之后还是存在一样的问题。loss函数没有 ...

非常抱歉没能解决你的问题。关于你遇到的问题,有几点可能需要注意:首先,确保参考矩阵`ref_CTable_T`和生成矩阵`gen_CTable`都是`torch.Tensor`类型,并且它们的`requires_grad`属性为`True`。如果其中任何一个不满足条件,梯度将无法正确传播。其次,确保在每次训练迭代时,参考矩阵`ref_CTable_T`和生成矩阵`gen_CTable`是不同的,否则损失将保持不变。最后,检查一下网络是否正常更新,也就是确保你的网络参数在训练过程中会有所改变。如果以上问题都没有解决你的困扰,请提供更多关于你的网络结构、数据准备和训练循环的代码细节。这样我可以更全面地了解你的情况并尝试给出更具体的建议。感谢你的耐心等待。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 10:25:29

FishC_GPT 发表于 2023-11-29 10:20
非常抱歉没能解决你的问题。关于你遇到的问题,有几点可能需要注意:首先,确保参考矩阵`ref_CTable_T`和 ...

ref_CTable_T矩阵也需要让它的`requires_grad`属性为`True`吗?它是我的参考矩阵,我不希望它在训练过程中发生变化,这种情况下也要让它的`requires_grad`属性为`True`吗?

FishC_GPT 发表于 2023-11-29 10:25:50

lqhenwunai 发表于 2023-11-29 10:25
ref_CTable_T矩阵也需要让它的`requires_grad`属性为` ...

如果你不希望参考矩阵`ref_CTable_T`在训练过程中发生变化,可以将其设为不需要计算梯度。你可以通过设置`requires_grad`属性为`False`来实现这一点。在计算损失时,确保生成矩阵`gen_CTable`的`requires_grad`属性为`True`即可。这样,只有生成矩阵`gen_CTable`的梯度会被计算和更新,而参考矩阵`ref_CTable_T`的梯度不会被计算。

以下是一个示例代码,展示如何在自定义损失函数中仅对生成矩阵计算梯度:

import torch
import torch.nn as nn

class MyLoss(nn.Module):
    def __init__(self, ref):
      super(MyLoss, self).__init__()
      self.ref = ref
   
    def forward(self, Y, gen_CTable):
      loss = ((Y - self.ref) ** 2).mean()
      return loss

# 创建参考矩阵
ref_CTable_T = torch.tensor(, dtype=torch.float32, requires_grad=False)

# 创建网络模型

# 定义自定义损失函数
loss_fn = MyLoss(ref_CTable_T)

# 在每个iteration中使用自定义损失函数进行前向传播和反向传播
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)

for epoch in range(num_epochs):
    optimizer.zero_grad()# 梯度清零
   
    # 前向传播
    Y = model(X)
   
    # 计算损失
    loss = loss_fn(Y, gen_CTable)
   
    # 反向传播
    loss.backward()
   
    # 更新参数
    optimizer.step()

在这个示例中,参考矩阵`ref_CTable_T`的`requires_grad`属性被设置为`False`,生成矩阵`gen_CTable`的`requires_grad`属性被设置为`True`,从而保证只有生成矩阵的梯度会被计算和更新。希望这能解决你的问题!

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 11:41:54

FishC_GPT 发表于 2023-11-29 10:25
如果你不希望参考矩阵`ref_CTable_T`在训练过程中发生变化,可以将其设为不需要计算梯度。你可以通过设置 ...

在给的这个MyLoss类的forward函数里,gen_CTable没有被用上,也要写在里面吗?

FishC_GPT 发表于 2023-11-29 11:42:10

lqhenwunai 发表于 2023-11-29 11:41
在给的这个MyLoss类的forward函数里,gen_CTable没有 ...

非常抱歉,之前的回答有误。在自定义损失函数的`forward()`方法中,只需要使用`Y`和`ref`来计算损失即可。`gen_CTable`不需要写在`forward()`方法中,因为它只是作为输入传递给自定义损失函数,并不直接参与损失函数的计算。以下是修改后的示例代码:import torchimport torch.nn as nnclass MyLoss(nn.Module):    def __init__(self, ref):      super(MyLoss, self).__init__()      self.ref = ref    def forward(self, Y):      loss = ((Y - self.ref) ** 2).mean()      return loss# 创建参考矩阵ref_CTable_T = torch.tensor(, dtype=torch.float32, requires_grad=False)# 创建网络模型# 定义自定义损失函数loss_fn = MyLoss(ref_CTable_T)# 在每个iteration中使用自定义损失函数进行前向传播和反向传播optimizer = torch.optim.SGD(model.parameters(), lr=0.001)for epoch in range(num_epochs):    optimizer.zero_grad()# 梯度清零      # 前向传播    Y = model(X)      # 计算损失    loss = loss_fn(Y)      # 反向传播    loss.backward()      # 更新参数    optimizer.step()在这个示例中,我们将生成矩阵`gen_CTable`从自定义损失函数的`forward()`方法中移除了,只保留了`Y`和`ref`用于损失函数的计算。这样就可以正确地计算和更新梯度了。非常抱歉之前的错误造成的困扰,希望这次能解决你的问题!

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 12:13:17

FishC_GPT 发表于 2023-11-29 11:42
非常抱歉,之前的回答有误。在自定义损失函数的`forward()`方法中,只需要使用`Y`和`ref`来计算损失即可 ...

以下是我的网络结构

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


from G02_dataset import myDataset
from G01_parameters import G_Parameter, MolPara


#in this attempt, use the random as input


class MyLoss2(nn.Module):
def __init__(self,ref):
super(MyLoss2,self).__init__()
self.ref = ref
def forward(self,gen_CTable):
loss = ((gen_CTable - self.ref) ** 2).mean()
return loss


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


def __init__(self,para):
super().__init__()
self.activation_func   = para.activation_func
self.loss_func         = para.loss_func
self.mat_shape         = para.mat_shape
self.increment         = para.increment
self.lr                  = para.lr
self.model_flag          = para.model_flag
self.Nlayer            = para.Nlayer
self.batch_size          = para.batch_size
self.Nsample             = para.Nsample
self.NAtom               = para.NAtom
self.thresh            = para.thresh
self.ref_CTable_T= torch.tensor(para.ref_CTable_T,dtype=torch.float32,requires_grad=False)
self.ref_CRow_T          = self.ref_CTable_T.view(1,self.NAtom*self.NAtom)

self.model               = self.G_model()


#no loss function according to the green book
# self.model.apply(weight_init)


self.optimiser         = para.optimizer(self.parameters(),lr=self.lr)

self.counter= 0
self.progress = []


##################################################3
def G_model(self):
model_flag = self.model_flag
Nlayer   = self.Nlayer
mat_shape= self.mat_shape
increment= self.increment
activation_func = self.activation_func


if model_flag==0: #MNIST
model = nn.Sequential(
   nn.Linear(100,128,bias=True),
   nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(128,256,bias=True),
   nn.BatchNorm1d(256, 0.8),
nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(256,512,bias=True),
   nn.BatchNorm1d(512, 0.8),
   nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(512,1024,bias=True),
   nn.BatchNorm1d(1024, 0.8),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(1024,784,bias=True),
nn.Tanh()
)
print("generator",model)
#-----------------------------------------------
if model_flag ==1: #simple
inp_dim = mat_shape*mat_shape
n1 = inp_dim
n2 = inp_dim + increment
n3 = inp_dim + increment*3
n4 = inp_dim + increment*2
model = nn.Sequential(
                  nn.Linear(n1, n2),
                  activation_func,
                  nn.Linear(n2, n3),
#nn.BatchNorm1d(n3,0.8),
      activation_func,
nn.Linear(n3,n2),
activation_func,
#nn.BatchNorm1d(n2,0.8),
activation_func,
nn.Linear(n2,n1),
      nn.Tanh()
         )
#----------------------------------------------
if model_flag==2:#increase then decrease
module_list=[]
inp_dim = mat_shape*mat_shape
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

model = nn.Sequential(*module_list)
#-----------------------------------------------------
if model_flag==3: #decrease then increase
module_list=[]
inp_dim = mat_shape*mat_shape
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

model = nn.Sequential(*module_list)
return model
#######################################################




def forward(self):
NAtom = self.NAtom

input_tensor = torch.rand(3*NAtom)
out=self.model(input_tensor)
return out


def train(self):
self.optimiser.zero_grad()
gen_geom= self.forward()


loss_fn    = MyLoss2(self.ref_CRow_T)
gen_CTable,gen_CRow_T = Tensor_Connectivity(self.NAtom, gen_geom)
loss       = loss_fn(gen_CRow_T)


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


loss.backward()
self.optimiser.step()
return loss






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()




#-----
def CalcBondLength(geom,i,j):
    ri=geom
    rj=geom
    rij=ri-rj
    rij=torch.linalg.norm(rij)
    return rij


def CalcAllBondLength(geom):
    NAtom=geom.shape
    res=[]
    bond_lengths={}
    for i in range(NAtom-1):
      for j in range(i+1,NAtom):
            rij = CalcBondLength(geom,i,j)
            res.append([,rij])
            bond_lengths)]=rij


    return res,bond_lengths


def Tensor_Connectivity(NAtom,flat_geom_T,thresh=1.6):
geom_T = flat_geom_T.view(NAtom,3)

bondlengthlist,bond_length_dict=CalcAllBondLength(geom_T)


ConnectTable = np.mat(np.zeros((NAtom,NAtom)),dtype=int)

for i in range(NAtom):
   for j in range(NAtom):
         key = str()
         if key in bond_length_dict.keys():
             value = bond_length_dict
         else:
             continue

         if value<=thresh:
             ConnectTable=1
ConnectTable = np.reshape(ConnectTable,(1,NAtom*NAtom))
gen_CRow_T   = torch.tensor(ConnectTable,dtype=torch.float32,requires_grad=True)
return ConnectTable,gen_CRow_T




if __name__=="__main__":






molinfo   = MolPara()
para      = G_Parameter(molinfo)
generator = Generator(para)


print(molinfo)
print(para)


Epoch=100
NAtom=molinfo.NAtom


for i in range(Epoch):
loss = generator.train()
if i%50==0:
print("Epoch ",i, "loss ", loss.item())
if abs(loss.item())<0.001:
print("hurray")
break


generator.plot_progress()

运行后损失函数还是不发生改变

FishC_GPT 发表于 2023-11-29 12:13:34

lqhenwunai 发表于 2023-11-29 12:13
以下是我的网络结构

import torch
import torch.n ...

你的代码中有一些错误,我进行了一些修改和调整。在给定的伪码中,损失函数是根据`gen_CTable`和`self.ref_CRow_T`计算的,但是在代码实现中,我并没有找到生成`gen_CTable`的相关代码。为了解决这个问题,你需要根据你的网络模型,在`forward()`方法中生成`gen_CTable`,然后将其作为输入传递给自定义损失函数。以下是对你给出的代码进行了一些修改的示例:torchimport torch.nn as nnimport torch.nn.functional as Fimport numpy as npclass MyLoss2(nn.Module):    def __init__(self, ref):      super(MyLoss2, self).__init__()      self.ref = ref    def forward(self, gen_CTable):      loss = ((gen_CTable - self.ref) ** 2).mean()      return lossclass Generator(nn.Module):    def __init__(self):      super(Generator, self).__init__()      # 定义你的网络结构      self.fc1 = nn.Linear(100, 128)      self.fc2 = nn.Linear(128, 256)      self.fc3 = nn.Linear(256, 512)      self.fc4 = nn.Linear(512, 1024)      self.fc5 = nn.Linear(1024, 784)    def forward(self, x):      x = F.leaky_relu(self.fc1(x), negative_slope=0.2)      x = F.leaky_relu(self.fc2(x), negative_slope=0.2)      x = F.leaky_relu(self.fc3(x), negative_slope=0.2)      x = F.leaky_relu(self.fc4(x), negative_slope=0.2)      x = torch.tanh(self.fc5(x))      return x# 创建参考矩阵ref_CRow_T = torch.tensor(...) # 你需要根据实际情况进行初始化生成器和自定义损失函数gen = Generator()loss_fn = MyLoss2(ref_CRow_T)# 在每个iteration中使用生成器和自定义损失函数进行前向传播和反向传播optimizer = torch.optim.SGD(gen.parameters(), lr=0.001)for epoch in range(num_epochs):    optimizer.zero_grad()    # 前向传播    gen_CTable = gen(torch.randn(batch_size, 100))    # 计算损失    loss = loss_fn(gen_CTable)    # 反向传播    loss.backward()    # 更新参数    optimizer.step()请注意,这只是对你给出代码的修改示例,具体的修改可能还需要根据你的实际需求进行调整。希望对你有所帮助!

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 12:24:05

FishC_GPT 发表于 2023-11-29 12:13
你的代码中有一些错误,我进行了一些修改和调整。在给定的伪码中,损失函数是根据`gen_CTable`和`self.re ...

现在我把gen_CTable 放到了foward里,但还是没有解决之前的问题。
另一方面,gen_CRow_T就是把gen_CTable进行扁平化后的结果。

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


from G02_dataset import myDataset
from G01_parameters import G_Parameter, MolPara


#in this attempt, use the random as input




class MyLoss2(nn.Module):
def __init__(self,ref):
super(MyLoss2,self).__init__()
self.ref = ref
def forward(self,gen_CTable):
loss = ((gen_CTable - self.ref) ** 2).mean()
return loss


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


def __init__(self,para):
super().__init__()
self.activation_func   = para.activation_func
self.loss_func         = para.loss_func
self.mat_shape         = para.mat_shape
self.increment         = para.increment
self.lr                  = para.lr
self.model_flag          = para.model_flag
self.Nlayer            = para.Nlayer
self.batch_size          = para.batch_size
self.Nsample             = para.Nsample
self.NAtom               = para.NAtom
self.thresh            = para.thresh
self.ref_CTable_T= torch.tensor(para.ref_CTable_T,dtype=torch.float32,requires_grad=False)
self.ref_CRow_T          = self.ref_CTable_T.view(1,self.NAtom*self.NAtom)

self.model               = self.G_model()


#no loss function according to the green book
# self.model.apply(weight_init)


self.optimiser         = para.optimizer(self.parameters(),lr=self.lr)

self.counter= 0
self.progress = []


##################################################3
def G_model(self):
model_flag = self.model_flag
Nlayer   = self.Nlayer
mat_shape= self.mat_shape
increment= self.increment
activation_func = self.activation_func


if model_flag==0: #MNIST
model = nn.Sequential(
   nn.Linear(100,128,bias=True),
   nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(128,256,bias=True),
   nn.BatchNorm1d(256, 0.8),
nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(256,512,bias=True),
   nn.BatchNorm1d(512, 0.8),
   nn.LeakyReLU(0.2, inplace=True),
   nn.Linear(512,1024,bias=True),
   nn.BatchNorm1d(1024, 0.8),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(1024,784,bias=True),
nn.Tanh()
)
print("generator",model)
#-----------------------------------------------
if model_flag ==1: #simple
inp_dim = mat_shape*mat_shape
n1 = inp_dim
n2 = inp_dim + increment
n3 = inp_dim + increment*3
n4 = inp_dim + increment*2
model = nn.Sequential(
                  nn.Linear(n1, n2),
                  activation_func,
                  nn.Linear(n2, n3),
#nn.BatchNorm1d(n3,0.8),
      activation_func,
nn.Linear(n3,n2),
activation_func,
#nn.BatchNorm1d(n2,0.8),
activation_func,
nn.Linear(n2,n1),
      nn.Tanh()
         )
#----------------------------------------------
if model_flag==2:#increase then decrease
module_list=[]
inp_dim = mat_shape*mat_shape
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

model = nn.Sequential(*module_list)
#-----------------------------------------------------
if model_flag==3: #decrease then increase
module_list=[]
inp_dim = mat_shape*mat_shape
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

model = nn.Sequential(*module_list)
return model
#######################################################


def forward(self):
NAtom = self.NAtom

input_tensor = torch.rand(3*NAtom)
out=self.model(input_tensor)
gen_CTable,gen_CRow_T = Tensor_Connectivity(self.NAtom, out)


return out,gen_CRow_T


def train(self):
self.optimiser.zero_grad()
gen_geom,gen_CRow_T= self.forward()


flag_loss=3
if flag_loss==1: #use custom loss function
batch_geom = #to maxium use existing code
loss = self.myLoss(batch_geom)
loss.requires_grad_(True)
if flag_loss==2: #use custom loss class
gen_CTable = torch.tensor(Tensor_Connectivity(self.NAtom, gen_geom),dtype=torch.float32)
gen_CTable = gen_CTable.view(1,self.NAtom*self.NAtom)
loss       = MyLoss.apply(gen_CTable,self.ref_CTable_T)
loss.requires_grad_(True)
if flag_loss==3:
loss_fn    = MyLoss2(self.ref_CRow_T)
loss       = loss_fn(gen_CRow_T)


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


loss.backward()
self.optimiser.step()
return loss,gen_geom


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()




#-----
def CalcBondLength(geom,i,j):
    ri=geom
    rj=geom
    rij=ri-rj
    rij=torch.linalg.norm(rij)
    return rij


def CalcAllBondLength(geom):
    NAtom=geom.shape
    res=[]
    bond_lengths={}
    for i in range(NAtom-1):
      for j in range(i+1,NAtom):
            rij = CalcBondLength(geom,i,j)
            res.append([,rij])
            bond_lengths)]=rij


    return res,bond_lengths


def Tensor_Connectivity(NAtom,flat_geom_T,thresh=1.6):
geom_T = flat_geom_T.view(NAtom,3)

bondlengthlist,bond_length_dict=CalcAllBondLength(geom_T)


ConnectTable = np.mat(np.zeros((NAtom,NAtom)),dtype=int)

for i in range(NAtom):
   for j in range(NAtom):
         key = str()
         if key in bond_length_dict.keys():
             value = bond_length_dict
         else:
             continue

         if value<=thresh:
             ConnectTable=1
ConnectTable = np.reshape(ConnectTable,(1,NAtom*NAtom))
gen_CRow_T   = torch.tensor(ConnectTable,dtype=torch.float32,requires_grad=True)
return ConnectTable,gen_CRow_T




if __name__=="__main__":






molinfo   = MolPara()
para      = G_Parameter(molinfo)
generator = Generator(para)


print(molinfo)
print(para)


Epoch=500
NAtom=molinfo.NAtom


for i in range(Epoch):
loss,out = generator.train()
if i%50==0:
print("Epoch ",i, "loss ", loss.item())
print(out.detach())
if abs(loss.item())<0.001:
print("hurray")
break




generator.plot_progress()
out = generator.forward()

FishC_GPT 发表于 2023-11-29 12:24:23

lqhenwunai 发表于 2023-11-29 12:24
现在我把gen_CTable 放到了foward里,但还是没有解决 ...

根据你提供的代码,我看到你已经将`gen_CTable`放在了`forward()`方法中,并且我也注意到了`gen_CRow_T`是将`gen_CTable`扁平化后的结果。但是,我注意到在损失函数的计算中使用了函数`Tensor_Connectivity()`,但是你并没有给出这个函数的定义。为了能够更好地帮助你,我需要你提供`Tensor_Connectivity()`函数的完整定义。

此外,你还需要确保自定义损失函数的反向传播在网络训练的过程中正确进行。一般情况下,PyTorch会自动计算损失函数对所有requires_grad=True的参数的梯度,然后使用反向传播算法更新参数。可以尝试将自定义损失函数的计算方式改为PyTorch内置的函数,例如MSELoss或CrossEntropyLoss,看看是否能够得到正确的梯度更新。

另外,你查看损失值没有变化可能是因为学习率设置得过大,导致参数更新过程中跳过了最优点。你可以尝试降低学习率,或者使用其他优化器(如Adam)来优化网络参数。

综上所述,你可以尝试以下几步来解决问题:
1. 确保`Tensor_Connectivity()`函数的定义被提供。
2. 尝试使用内置的损失函数(如MSELoss或CrossEntropyLoss)来替换自定义损失函数,查看是否能够得到正确的梯度更新。
3. 调整学习率或尝试其他优化器,以确保参数的更新过程能够收敛到最优点。

希望这些建议对你有所帮助!如果还有其他问题,请随时提问。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 12:28:48

FishC_GPT 发表于 2023-11-29 12:24
根据你提供的代码,我看到你已经将`gen_CTable`放在了`forward()`方法中,并且我也注意到了`gen_CRow_T` ...

针对给出的建议:
1)以下是Tensor_Connectivity()函数的定义及相关函数的定义。
2)试过采用内置损失函数如MSELoss, BCELoss等,都得到一样的问题,即损失函数不变
3)目前采用的学习率是0.01, 尝试过0.001和0.0001,遇到同样的问题。改变优化器同样会遇到相同的问题。
#-----
def CalcBondLength(geom,i,j):
    ri=geom
    rj=geom
    rij=ri-rj
    rij=torch.linalg.norm(rij)
    return rij


def CalcAllBondLength(geom):
    NAtom=geom.shape
    res=[]
    bond_lengths={}
    for i in range(NAtom-1):
      for j in range(i+1,NAtom):
            rij = CalcBondLength(geom,i,j)
            res.append([,rij])
            bond_lengths)]=rij


    return res,bond_lengths


def Tensor_Connectivity(NAtom,flat_geom_T,thresh=1.6):
geom_T = flat_geom_T.view(NAtom,3)

bondlengthlist,bond_length_dict=CalcAllBondLength(geom_T)


ConnectTable = np.mat(np.zeros((NAtom,NAtom)),dtype=int)

for i in range(NAtom):
   for j in range(NAtom):
         key = str()
         if key in bond_length_dict.keys():
             value = bond_length_dict
         else:
             continue

         if value<=thresh:
             ConnectTable=1
ConnectTable = np.reshape(ConnectTable,(1,NAtom*NAtom))
gen_CRow_T   = torch.tensor(ConnectTable,dtype=torch.float32,requires_grad=True)
return ConnectTable,gen_CRow_T

FishC_GPT 发表于 2023-11-29 12:29:10

lqhenwunai 发表于 2023-11-29 12:28
针对给出的建议:
1)以下是Tensor_Connectivity()函 ...

从你提供的代码来看,我发现在函数`Tensor_Connectivity()`中存在一些问题,这可能导致你得不到正确的损失函数的值。以下是修复过的代码:

def CalcBondLength(geom, i, j):
    ri = geom
    rj = geom
    rij = torch.linalg.norm(ri - rj)
    return rij

def CalcAllBondLength(geom):
    NAtom = geom.shape
    res = []
    bond_lengths = {}
    for i in range(NAtom-1):
      for j in range(i+1, NAtom):
            rij = CalcBondLength(geom, i, j)
            res.append()
            bond_lengths = rij
    return res, bond_lengths

def Tensor_Connectivity(NAtom, flat_geom_T, thresh=1.6):
    geom_T = flat_geom_T.view(NAtom, 3)
    bondlengthlist, bond_length_dict = CalcAllBondLength(geom_T)
    ConnectTable = np.zeros((NAtom, NAtom), dtype=int)
    for bond in bondlengthlist:
      i, j, rij = bond
      if rij < thresh:
            ConnectTable = 1
            ConnectTable = 1
    return ConnectTable

在`Tensor_Connectivity()`函数中,我修复了`CalcAllBondLength()`函数的调用和`ConnectTable`的返回。请注意,这里使用了一个阈值(`thresh`)来判断是否连接两个原子。

另外,为了确保反向传播正常工作,请确保网络模型中的所有参数都设置为`requires_grad=True`。你可以使用以下代码来检查是否更新了模型的参数:

for param in model.parameters():
    print(param.requires_grad)

如果任何一个参数的`requires_grad`属性为`False`,则需要将其设置为`True`。

最后,你可以尝试以下几种方法来解决梯度更新问题:
- 尝试不同的学习率,并逐渐降低学习率的大小。
- 检查网络模型的架构和超参数设定是否合理。
- 使用其他优化器的变体,如Adam、RMSprop等。
- 尝试从头开始训练网络模型,而不是加载预训练模型。

希望这些建议能够帮助你解决问题!如果还有其他疑问,请随时提问。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。

lqhenwunai 发表于 2023-11-29 13:49:48

FishC_GPT 发表于 2023-11-29 12:29
从你提供的代码来看,我发现在函数`Tensor_Connectivity()`中存在一些问题,这可能导致你得不到正确的损 ...

我按照建议更改了Tensor_Connectivity函数,但是损失函数还是没有变化。

打印model.parameters的param.requires_grad,显示都为True

换了几种优化器,和学习率,并且没有加载预训练模型,但是损失函数还是没有变化。

FishC_GPT 发表于 2023-11-29 13:50:03

lqhenwunai 发表于 2023-11-29 13:49
我按照建议更改了Tensor_Connectivity函数,但是损失 ...

感谢您的反馈。虽然我无法直接查看您的完整代码,但是我可以提供一些常见的问题和解决方法,希望能帮助到您:

1. 确保优化器的参数和模型参数匹配:请确保您将模型的参数传递给了优化器。例如,使用`optim.SGD`的优化器应该类似于 `optimizer = optim.SGD(model.parameters(), lr=0.001)`。

2. 检查数据是否正确传递:请确保您在每个训练迭代中正确地计算了输入`X`和真实标签`ref`,并将它们传递给了模型进行前向传播。

3. 检查损失函数的计算方式:请确保在自定义损失函数中,您正确地计算了损失函数的值。在损失函数中,您可以使用PyTorch中的任何张量运算和函数。

4. 确认模型是否处于训练模式:在训练过程中,确保将模型设置为`model.train()`。

5. 调试打印语句:您可以在代码中插入一些打印语句,以便查看变量的值和梯度的情况,从而找出问题所在。

如果您已经尝试了以上的方法,并且仍然无法解决问题,请提供更多的代码细节,特别是关于模型和训练过程的部分,以便更好地了解您的情况并提供针对性的解决方案。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。
页: [1] 2
查看完整版本: 神经网络自定义损失函数问题求助