如何根据loss值来计算小批量的梯度?

一直有一个问题,就是小批量梯度下降的时候把批量的损失累加后怎么根据累加得到的loss值来计算梯度呀,loss应该是一个等高线圈吧,怎么确定从哪个点开始下降呢?

  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7763484
  • 这篇博客你也可以参考下:梯度、激活函数 及Loss的梯度
  • 除此之外, 这篇博客: Loss及其梯度中的 一、常见的Loss函数类型 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    1. Mean squared error(均方差,mse)
      1. 基本形式
        1. loss=∑[y−fθ(x)]2loss=\sum[y-f_\theta(x)]^2loss=[yfθ(x)]2
        2. L2−norm=∣∣y−fθ(x)∣∣2L2-norm=||y-f_\theta(x)||_2L2norm=yfθ(x)2
        3. loss=norm(y−fθ(x))2loss=norm(y-f_\theta(x))^2loss=norm(yfθ(x))2
      2. mse求导
        ▽loss▽θ=2∗∑[y−fθ(x)]∗▽fθ(x)▽θ \frac{\triangledown loss}{\triangledown \theta}=2*\sum{\left[ y-f_{\theta}\left( x \right) \right]}*\frac{\triangledown f_{\theta}\left( x \right)}{\triangledown \theta} θloss=2[yfθ(x)]θfθ(x)
    2. Cross Entropy Loss(交叉熵)
      1. 可用于二分类(binary)和多分类(multi-class)问题
      2. 使用时常与softmax搭配使用
  • 以下回答由chatgpt基于相关博客总结生成:

    对于小批量梯度下降,梯度的计算方法如下:

    1.随机选取一部分数据(即一个batch)作为训练数据,输入到网络中进行前向传播得到预测值。

    2.根据预测值和真实值计算损失函数的值(一般使用交叉熵或均方误差等)。

    3.计算损失函数对每一个可训练参数的偏导数,即求梯度。

    4.根据梯度更新参数,下次使用时继续重复上述过程。

    对于利用损失函数的值来确定起始点,可以先对数据集进行预处理,然后使用训练好的模型对数据集中的所有样本进行前向传播得到预测值,再根据预测值和真实值计算损失函数值,取平均值作为训练集的损失函数值。然后使用这个损失函数值来确定起始点,具体方法如下:

    1.设定一个初始参数值(可以使用模型预测得到的参数进行初始化)。

    2.计算损失函数值并记录。

    3.对于每一个参数,计算损失函数值在该点向前或向后微小变化时的差值,即数值梯度。

    4.使用数值梯度来更新参数值,并重复2、3步骤计算损失函数值。

    5.重复4步骤,直到损失函数收敛或达到最大迭代次数。

    代码实现如下:

    import torch
    import torch.nn.functional as F
    
    def calculate_gradient(model, loss_fn, loader):
        """
        计算小批量梯度下降中的梯度
        :param model: 模型
        :param loss_fn: 损失函数
        :param loader: 训练数据加载器
        :return: 模型的梯度
        """
        model.train()
        grad = []
        for batch_idx, (data, target) in enumerate(loader):
            data, target = data.cuda(), target.cuda()
    
            optimizer.zero_grad()
    
            output = model(data)
            loss = loss_fn(output, target)
            loss.backward()
            grad.append([p.grad.cpu().numpy() for p in model.parameters()])
    
            optimizer.step()
    
        return [torch.from_numpy(np.array(g)).cuda().mean(dim=0) for g in zip(*grad)]
    
    def determine_starting_point(model, loss_fn, loader):
        """
        利用损失函数的值来确定起始点
        :param model: 模型
        :param loss_fn: 损失函数
        :param loader: 训练数据加载器
        :return: 起始点的参数
        """
        model.train()
    
        # 计算整个数据集的损失函数值
        total_loss = 0.0
        for batch_idx, (data, target) in enumerate(loader):
            data, target = data.cuda(), target.cuda()
    
            output = model(data)
            loss = loss_fn(output, target)
            total_loss += loss.item() * len(data)
    
        # 取平均值作为训练集的损失函数值
        total_loss /= len(loader.dataset)
    
        # 初始化参数
        params = [p.clone().detach().requires_grad_(True) for p in model.parameters()]
    
        # 计算参数的数值梯度并更新参数
        lr = 1e-3
        max_iter = 1000
        for i in range(max_iter):
            grad = calculate_gradient(model, loss_fn, loader)
            with torch.no_grad():
                for p, g in zip(params, grad):
                    p -= lr * (g / (2 * abs(total_loss)))
    
            # 计算新的损失函数值并记录
            model.load_state_dict({name: value for name, value in zip(model.state_dict().keys(), params)})
            model.eval()
            new_loss = 0.0
            for batch_idx, (data, target) in enumerate(loader):
                data, target = data.cuda(), target.cuda()
    
                output = model(data)
                loss = loss_fn(output, target)
                new_loss += loss.item() * len(data)
            new_loss /= len(loader.dataset)
    
            # 如果损失函数的变化不再变化就停止迭代
            if abs(new_loss - total_loss) < 1e-6:
                break
            total_loss = new_loss
    
        return model.state_dict()
    

    需要注意的是,这种方式仅适用于较小的数据集和较简单的模型,因为计算数值梯度的过程会耗费大量的时间和计算资源。对于更大的数据集和更复杂的模型,可以使用高阶优化算法(如L-BFGS)来求解。