zzknightReal 2023-04-23 11:08 采纳率: 0%
浏览 136
已结题

Pytorch 求二阶导数结果总是为零?

我用pytorch的autograd求output对input的二阶导数,结果总是0。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

class MTLModel(nn.Module):
    def __init__(self, input_size, hidden_sizes, num_tasks):
        super(MTLModel, self).__init__()
        self.shared_layers = nn.Sequential(
            nn.Linear(input_size, hidden_sizes[0]),
            nn.ReLU()
        )
        for i in range(len(hidden_sizes) - 1):
            self.shared_layers.add_module(f'hidden_layer_{i+1}', nn.Linear(hidden_sizes[i], hidden_sizes[i+1]))
            self.shared_layers.add_module(f'relu_{i+1}', nn.ReLU())

        self.task_specific_layers = nn.ModuleList()
        for i in range(num_tasks):
            self.task_specific_layers.append(nn.Linear(hidden_sizes[-1], 1))

    def forward(self, x):
        shared_output = self.shared_layers(x)
        task_outputs = []
        for task_layer in self.task_specific_layers:
            task_output = task_layer(shared_output)
            task_outputs.append(task_output)
        return task_outputs

# Define the training function
def train(model, train_data, train_targets, num_epochs, batch_size, learning_rate, alpha, gamma):
    criterion = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)

    num_batches = len(train_data) // batch_size

    for epoch in range(num_epochs):
        epoch_loss = 0.0
        epoch_monotonicity_penalty = 0.0*np.ones(train_targets.shape[1])
        epoch_slope_penalty = 0.0
        epoch_output2_constraint_penalty = 0.0
        epoch_output3_constraint_penalty = 0.0
        epoch_slope_penalty = 0.0
        for batch in range(num_batches):
            batch_data = train_data[batch*batch_size:(batch+1)*batch_size]
            batch_targets = train_targets[batch*batch_size:(batch+1)*batch_size]
            batch_data = torch.tensor(batch_data, dtype=torch.float32, requires_grad=True)  # set requires_grad to True
            batch_targets = torch.tensor(batch_targets, dtype=torch.float32)
            optimizer.zero_grad()
            task_outputs = model(batch_data)
            task_gradients = []
            task_gradient2s = []
            task_losses = []
            for i, task_output in enumerate(task_outputs):
                task_loss = criterion(task_output.squeeze(), batch_targets[:,i])
                task_losses.append(task_loss)
                
                # Apply the monotonicity constraint
                task_gradient, = torch.autograd.grad(task_output.sum(), batch_data, create_graph=True, retain_graph=True)
                monotonicity_penalty = -task_gradient.mean().clamp(min=0.0)
                task_loss += alpha[i] * monotonicity_penalty
                epoch_monotonicity_penalty[i] += monotonicity_penalty.item()
                
                task_gradient2, = torch.autograd.grad(task_gradient.sum(), batch_data, create_graph=True, retain_graph=True)
                
                print('1st gradient\n',task_gradient)
                print('2nd gradient\n',task_gradient2)
                
            loss = sum(task_losses)
            loss.backward()
            optimizer.step()
            epoch_loss += loss.item()
            
        print('Epoch %d Loss: %.4f Slope Penalty: %.4f ' % (epoch+1, epoch_loss/num_batches, epoch_slope_penalty))
        print('epoch_monotonicity_penalty',epoch_monotonicity_penalty)
#%%
# Generate random data
num_samples = 100
num_features = 1
np.random.seed(100)
data = np.linspace(0, 1, num=num_samples).reshape(num_samples,1)
targets = np.zeros((num_samples, 3))
targets[:,0] = -0.5+0.5*np.cos(data[:,0]) + 0.2*data[:,0]**2+0.1*np.random.normal(size=(num_samples))
targets[:,1] = data[:,0]**3 + 0.1*np.random.normal(size=(num_samples))
targets[:,2] = 2*data[:,0]**4 + 0.1*np.random.normal(size=(num_samples))


# Define the model
input_size = num_features
hidden_size = [64,128,64]
num_tasks = 3
model = MTLModel(input_size, hidden_size, num_tasks)

# Define the training parameters
num_epochs = 200
batch_size = 32
learning_rate = 0.001
alpha = [0,0,0] #[0,0,0]

gamma = 0

# Train the model
train(model, data, targets, num_epochs, batch_size, learning_rate, alpha, gamma)


  • 写回答

10条回答

  • Leodong. 2023-04-23 11:15
    关注

    该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
    通过仔细观察代码,我发现二阶导数为零的原因在于在计算二阶导数时,只对第一个输出进行了计算,而没有对其他输出进行计算。具体来说,在代码中的以下这行:

    task_gradient2, = torch.autograd.grad(task_gradient.sum(), batch_data, create_graph=True, retain_graph=True)
    

    只对task_gradient的和进行了二阶导数计算,而没有对其他输出的梯度进行计算。因此,需要对所有输出的梯度进行计算,并将它们的二阶导数累加起来,才能得到正确的结果。

    为了修复这个问题,需要对代码进行如下修改:

    for i, task_output in enumerate(task_outputs):
        task_loss = criterion(task_output.squeeze(), batch_targets[:,i])
        task_losses.append(task_loss)
    
        # Apply the monotonicity constraint
        task_gradient, = torch.autograd.grad(task_output.sum(), batch_data, create_graph=True, retain_graph=True)
        monotonicity_penalty = -task_gradient.mean().clamp(min=0.0)
        task_loss += alpha[i] * monotonicity_penalty
        epoch_monotonicity_penalty[i] += monotonicity_penalty.item()
    
        # Compute the second-order gradient for all outputs
        task_gradients.append(task_gradient)
        task_gradient2, = torch.autograd.grad(task_gradient.sum(), batch_data, create_graph=True, retain_graph=True)
        task_gradient2s.append(task_gradient2)
    
    # Compute the final loss and backpropagate
    task_gradients = torch.stack(task_gradients, dim=0)
    task_gradient2s = torch.stack(task_gradient2s, dim=0)
    loss = sum(task_losses)
    loss.backward()
    
    # Compute the second-order derivative for all outputs
    task_gradients2 = torch.autograd.grad(task_gradients, batch_data, grad_outputs=task_gradient2s, create_graph=True, retain_graph=True)
    

    在修改后的代码中,我们首先定义了两个新的列表task_gradientstask_gradient2s,用于存储所有输出的一阶梯度和二阶梯度。在每个任务完成一阶梯度和二阶梯度的计算后,将它们分别添加到相应的列表中。然后,在完成所有任务的一阶梯度和二阶梯度的计算后,我们使用torch.stack()函数将它们分别堆叠成张量,以便进行后续的二阶导数计算。最后,我们使用torch.autograd.grad()函数计算所有输出的二阶导数,并将它们存储在task_gradients2列表中。

    修改后的完整代码如下:

    import torch
    import torch.nn as nn
    import torch.optim as optim
    import numpy as np
    
    class MTLModel(nn.Module):
        def __init__(self, input_size, hidden_sizes, num_tasks):
            super(MTLModel, self).__init__()
            self.shared_layers = nn.Sequential(
                nn.Linear(input_size, hidden_sizes[0]),
                nn.ReLU()
            )
            for i in range(len(hidden_sizes) - 1):
                self.shared_layers.add_module(f'hidden_layer_{i+1}', nn.Linear(hidden_sizes[i], hidden_sizes[i+1]))
                self.shared_layers.add_module(f'relu_{i+1}', nn.ReLU())
    
            self.task_specific_layers = nn.ModuleList()
            for i in range(num_tasks):
                self.task_specific_layers.append(nn.Linear(hidden_sizes[-1], 1))
    
        def forward(self, x):
            shared_output = self.shared_layers(x)
            task_outputs = []
            for task_layer in self.task_specific_layers:
                task_output = task_layer(shared_output)
                task_outputs.append(task_output)
            return task_outputs
    
    # Define the training function
    def train(model, train_data, train_targets, num_epochs, batch_size, learning_rate, alpha, gamma):
        criterion = nn.MSELoss()
        optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    
        # Initialize the monotonicity penalty for each task
        epoch_monotonicity_penalty = [0.0] * len(alpha)
    
        for epoch in range(num_epochs):
            # Shuffle the data
            num_samples = train_data.shape[0]
            permutation = np.random.permutation(num_samples)
            train_data = train_data[permutation]
            train_targets = train_targets[permutation]
    
            # Train the model in batches
            for batch_start in range(0, num_samples, batch_size):
                batch_end = batch_start + batch_size
                batch_data = torch.tensor(train_data[batch_start:batch_end], dtype=torch.float32)
                batch_targets = torch.tensor(train_targets[batch_start:batch_end], dtype=torch.float32)
    
                # Forward pass
                task_outputs = model(batch_data)
                task_losses = []
                task_gradients = []
                task_gradient2s = []
                for i, task_output in enumerate(task_outputs):
                    task_loss = criterion(task_output.squeeze(), batch_targets[:,i])
                    task_losses.append(task_loss)
    
                    # Apply the monotonicity constraint
                    task_gradient, = torch.autograd.grad(task_output.sum(), batch_data, create_graph=True, retain_graph=True)
                    monotonicity_penalty = -task_gradient.mean().clamp(min=0.0)
                    task_loss += alpha[i] * monotonicity_penalty
                    epoch_monotonicity_penalty[i] += monotonicity_penalty.item()
    
                    # Compute the first-order gradient for all outputs
                    task_gradients.append(task_gradient)
    
                    # Compute the second-order gradient for all outputs
                    task_gradient2, = torch.autograd.grad(task_gradient.sum(), batch_data, create_graph=True, retain_graph=True)
                    task_gradient2s.append(task_gradient2)
    
                # Compute the final loss and backpropagate
                task_gradients = torch.stack(task_gradients, dim=0)
                task_gradient2s = torch.stack(task_gradient2s, dim=0)
                loss = sum(task_losses)
                loss.backward()
    
                # Compute the second-order derivative for all outputs
                task_gradients2 = torch.autograd.grad(task_gradients, batch_data, grad_outputs=task_gradient2s, create_graph=True, retain_graph=True)
    
                # Apply the monotonicity constraint on the second-order derivative
                for i, task_gradient2 in enumerate(task_gradients2):
                    monotonicity_penalty = -task_gradient2.mean().clamp(min=0.0)
                    loss += gamma[i] * monotonicity_penalty
                    epoch_monotonicity_penalty[i] += monotonicity_penalty.item()
    
                # Update the model parameters
                optimizer.step()
                optimizer.zero_grad()
    
            # Print the epoch loss and monotonicity penalty
            epoch_loss = loss.item()
            print(f'Epoch {epoch+1}/{num_epochs}, Loss: {epoch_loss:.4f}', end='')
            for i, penalty in enumerate(epoch_monotonicity_penalty):
                print(f', Task {i+1} Monotonicity Penalty: {penalty:.4f}', end='')
                epoch_monotonicity_penalty[i] = 0.0
            print()
    
    # Generate synthetic data
    np.random.seed(0)
    input_size = 1
    hidden_sizes = [10, 10, 10]
    num_tasks = 3
    num_samples = 1000
    batch_size = 32
    learning_rate = 0.001
    num_epochs = 100
    alpha = [0.1, 0.1, 0.1]
    gamma = [0.01, 0.01, 0.01]
    
    train_data = np.random.uniform(0.0, 1.0, size=(num_samples, input_size))
    train_targets = np.zeros((num_samples, num_tasks))
    for i in range(num_tasks):
        train_targets[:,i] = np.sin(train_data[:,0] * (2*np.pi*(i+1))) + np.random.normal(0.0, 0.1, size=num_samples)
    
    # Train the model
    model = MTLModel(input_size, hidden_sizes, num_tasks)
    train(model, train_data, train_targets, num_epochs, batch_size, learning_rate, alpha, gamma)
    

    如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

    评论

报告相同问题?

问题事件

  • 系统已结题 5月1日
  • 赞助了问题酬金20元 4月24日
  • 赞助了问题酬金20元 4月23日
  • 赞助了问题酬金20元 4月23日
  • 展开全部