NeuralForecast VanillaTransformer MAE损失函数

2024-06-05 22:20

本文主要是介绍NeuralForecast VanillaTransformer MAE损失函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

NeuralForecast VanillaTransformer MAE损失函数

flyfish

nn.L1Loss() 和 自定义的class MAE(BasePointLoss): 在本质上都是计算 Mean Absolute Error (MAE),但是它们有一些不同之处,主要在于定制化和功能上的差异。
写一个自定义的MAE完整示例代码


import mathfrom typing import Optional, Union, Tupleimport math
import numpy as np
import torchimport torch.nn as nn
import torch.nn.functional as F
def _divide_no_nan(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:"""Auxiliary funtion to handle divide by 0"""div = a / bdiv[div != div] = 0.0div[div == float("inf")] = 0.0return div
def _weighted_mean(losses, weights):"""Compute weighted mean of losses per datapoint."""return _divide_no_nan(torch.sum(losses * weights), torch.sum(weights))
class BasePointLoss(torch.nn.Module):"""Base class for point loss functions.**Parameters:**<br>`horizon_weight`: Tensor of size h, weight for each timestamp of the forecasting window. <br>`outputsize_multiplier`: Multiplier for the output size. <br>`output_names`: Names of the outputs. <br>"""def __init__(self, horizon_weight, outputsize_multiplier, output_names):super(BasePointLoss, self).__init__()if horizon_weight is not None:horizon_weight = torch.Tensor(horizon_weight.flatten())self.horizon_weight = horizon_weightself.outputsize_multiplier = outputsize_multiplierself.output_names = output_namesself.is_distribution_output = Falsedef domain_map(self, y_hat: torch.Tensor):"""Univariate loss operates in dimension [B,T,H]/[B,H]This changes the network's output from [B,H,1]->[B,H]"""return y_hat.squeeze(-1)def _compute_weights(self, y, mask):"""Compute final weights for each datapoint (based on all weights and all masks)Set horizon_weight to a ones[H] tensor if not set.If set, check that it has the same length as the horizon in x."""if mask is None:mask = torch.ones_like(y, device=y.device)if self.horizon_weight is None:self.horizon_weight = torch.ones(mask.shape[-1])else:assert mask.shape[-1] == len(self.horizon_weight), "horizon_weight must have same length as Y"weights = self.horizon_weight.clone()weights = torch.ones_like(mask, device=mask.device) * weights.to(mask.device)return weights * maskclass MAE(BasePointLoss):"""Mean Absolute ErrorCalculates Mean Absolute Error between`y` and `y_hat`. MAE measures the relative predictionaccuracy of a forecasting method by calculating thedeviation of the prediction and the truevalue at a given time and averages these devationsover the length of the series.$$ \mathrm{MAE}(\\mathbf{y}_{\\tau}, \\mathbf{\hat{y}}_{\\tau}) = \\frac{1}{H} \\sum^{t+H}_{\\tau=t+1} |y_{\\tau} - \hat{y}_{\\tau}| $$**Parameters:**<br>`horizon_weight`: Tensor of size h, weight for each timestamp of the forecasting window. <br>"""def __init__(self, horizon_weight=None):super(MAE, self).__init__(horizon_weight=horizon_weight, outputsize_multiplier=1, output_names=[""])def __call__(self,y: torch.Tensor,y_hat: torch.Tensor,mask: Union[torch.Tensor, None] = None,):"""**Parameters:**<br>`y`: tensor, Actual values.<br>`y_hat`: tensor, Predicted values.<br>`mask`: tensor, Specifies datapoints to consider in loss.<br>**Returns:**<br>`mae`: tensor (single value)."""losses = torch.abs(y - y_hat)weights = self._compute_weights(y=y, mask=mask)return _weighted_mean(losses=losses, weights=weights)# 定义简单的线性模型示例
class SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.linear = nn.Linear(10, 1)  # 10个输入特征,1个输出def forward(self, x):return self.linear(x)# 初始化模型和损失函数
model = SimpleModel()
mae_loss = MAE(horizon_weight=None)# 生成示例数据
# 批次大小为5,时间步长为10,假设预测未来一个时间步的值
batch_size = 5
time_steps = 10
input_features = 10# 随机生成输入数据和真实标签
x = torch.randn(batch_size, input_features)
y = torch.randn(batch_size, 1)  # 真实值# 生成预测值
y_hat = model(x)# 调用 domain_map 函数
y_hat_mapped = mae_loss.domain_map(y_hat)# 调用损失函数
# 这里假设 mask 为 None,表示考虑所有数据点
mae_value = mae_loss(y, y_hat_mapped, mask=None)# 打印MAE值
print("Mean Absolute Error (MAE):", mae_value.item())

M A E = 1 H ∑ i = 1 H ∣ y i − y ^ i ∣ \mathrm{MAE} = \frac{1}{H} \sum_{i=1}^{H} | y_i - \hat{y}_i | MAE=H1i=1Hyiy^i

y i y_i yi表示实际值。
y ^ i \hat{y}_i y^i表示预测值。
H H H表示预测的时间步数或样本数量

这两个函数是用来计算加权平均损失的辅助函数。

_divide_no_nan(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:

这个函数用来处理两个张量相除时出现除以零的情况。它首先计算两个张量相除的结果 div,然后将结果中的 NaN 值(由除以零导致)替换为 0.0,并将结果中的正无穷值替换为 0.0,最后返回处理后的结果。

如果 b 中包含 0,那么 a / b 的计算会产生除以零的情况,这会导致结果中出现 NaN(“Not a Number”)或正无穷大(inf)值。_divide_no_nan 函数的目的是处理这些情况,确保输出结果中没有 NaN 或无穷大值。

让我们详细说明这一过程:

初始计算:
div = a / b 进行逐元素相除,如果 b 中有 0,结果 div 中相应位置会包含 NaN 或 inf。

替换 NaN 值:
div[div != div] = 0.0 这一行代码使用了一个技巧:由于 NaN 不等于任何值,包括它自己,div != div 会在 NaN 所在的位置返回 True。于是,div[div != div] 会选中所有 NaN 并将其设置为 0.0。

替换 inf 值:
div[div == float(“inf”)] = 0.0 这一行代码将所有正无穷大(inf)值替换为 0.0。

因此,如果 b 包含 0,函数 _divide_no_nan 会确保相应位置的结果是 0.0,而不是 NaN 或 inf。这保证了计算的稳定性和结果的可用性。

def _divide_no_nan(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:div = a / bdiv[div != div] = 0.0div[div == float("inf")] = 0.0return diva = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([0.0, 2.0, 0.0])result = _divide_no_nan(a, b)
print(result)  # 输出 tensor([0., 1., 0.])

在这个例子中,a / b 会生成 [inf, 1.0, inf],然后 div[div != div] = 0.0 将 NaN 转换为 0.0(但在这个例子中没有 NaN),div[div == float(“inf”)] = 0.0 将 inf 转换为 0.0,最终结果是 [0.0, 1.0, 0.0]。

_weighted_mean(losses, weights):

这个函数用来计算加权平均损失。它接收两个参数,losses 表示每个数据点的损失值,weights 表示每个数据点的权重。函数首先计算每个损失值乘以相应的权重,然后将所有加权损失值相加,最后除以所有权重的总和。在这个过程中,_divide_no_nan 函数被用来处理除以零的情况,确保计算的稳定性。

BasePointLoss

BasePointLoss 是一个 PyTorch 模块类,用于定义时间序列预测中的基础点损失函数。它提供了一些通用的功能和参数设置,这些功能和设置可以在具体的点损失函数(如均方误差 MSE 或平均绝对误差 MAE)中继承和使用。

主要功能和参数
以下是 BasePointLoss 类的主要功能和参数说明:

horizon_weight:
这是一个大小为 h 的张量,表示预测窗口中每个时间戳的权重。如果没有提供,它将在计算时设置为全 1 的张量。

outputsize_multiplier:
这是一个用于调整输出大小的乘数。

output_names:
这是一个列表,包含输出的名称。

该方法根据 horizon_weight 和 mask 计算每个数据点的权重。如果 horizon_weight 未设置,它将默认为全 1 的张量;否则,它会检查 horizon_weight 的长度是否与 y 的最后一维相同。

import torch# 定义示例 horizon_weight 和 mask
horizon_weight = torch.Tensor([0.1, 0.3, 0.6])
mask = torch.Tensor([[1, 0, 1], [1, 1, 0]])# 定义 y(实际值),这里只是为了展示维度,具体值不影响计算权重
y = torch.Tensor([[2, 3, 4],[1, 2, 3]])# 模拟 BasePointLoss 类的 _compute_weights 方法
def compute_weights(horizon_weight, y, mask):if mask is None:mask = torch.ones_like(y, device=y.device)if horizon_weight is None:horizon_weight = torch.ones(mask.shape[-1])else:assert mask.shape[-1] == len(horizon_weight), "horizon_weight must have same length as Y"weights = horizon_weight.clone()weights = torch.ones_like(mask, device=mask.device) * weights.to(mask.device)return weights * mask# 计算权重
final_weights = compute_weights(horizon_weight, y, mask)# 打印最终权重
print("Final Weights:")
print(final_weights)

horizon_weight:
定义每个时间点的权重。例如,[0.1, 0.3, 0.6] 表示第一个时间点的权重为 0.1,第二个时间点为 0.3,第三个时间点为 0.6。

mask:
定义哪些数据点应被考虑。例如,[[1, 0, 1], [1, 1, 0]] 表示第一个样本的第二个时间点和第二个样本的第三个时间点不被考虑。

y:
实际值,仅用于展示维度。在这个例子中,假设每个样本在时间维度上有 3 个点。

compute_weights:
计算最终的权重。如果 mask 为 None,则默认为全 1。如果 horizon_weight 为 None,则默认为全 1。最终权重是 horizon_weight 和 mask 的逐元素乘积。

输出结果

Final Weights:
tensor([[0.1000, 0.0000, 0.6000],[0.1000, 0.3000, 0.0000]])

这个结果表明,权重和掩码的结合使得某些数据点被赋予了相应的权重,而被掩盖的点(即掩码为 0 的点)的权重为 0。

使用MAE 损失的原因

鲁棒性:
MAE 对于异常值的影响比均方误差 (MSE) 小,因为它计算的是绝对误差,而不是平方误差。这使得 MAE 在存在异常值或噪声的时间序列中表现更加稳健。

简单易解释:
MAE 直接衡量预测值与真实值之间的平均绝对差异,这使得其结果容易解释。它表示的是预测值与真实值之间的平均距离,这在实际应用中非常直观。

公平的误差惩罚:
MAE 对每个数据点的误差惩罚是线性的,这意味着每个预测误差都会被同等对待。相比之下,MSE 会对较大的误差赋予更高的惩罚,这在某些应用场景下可能会导致不必要的偏差。

nn.L1Loss和自定义的MAE比较下,体现一下自定义的功能

nn.L1Loss 的调用

PyTorch 内置的损失函数,用于计算预测值和真实值之间的平均绝对误差。其使用非常简单,默认情况下对每个数据点给予相同的权重,没有其他附加功能。

import torch
import torch.nn as nn# Example usage of nn.L1Loss
loss_fn = nn.L1Loss()
y = torch.tensor([1.0, 2.0, 3.0])
y_hat = torch.tensor([1.5, 2.5, 3.5])
loss = loss_fn(y_hat, y)
print(loss.item())  # Output: 0.5

class MAE(BasePointLoss) 的调用

这个自定义的 MAE 类继承自 BasePointLoss,是一个更复杂和定制化的实现。它具有以下特点:

可选的时间权重(horizon_weight):
MAE 类可以接受一个时间权重向量 horizon_weight,对预测窗口内的每个时间点赋予不同的权重。这在一些应用场景中非常有用,例如希望对特定时间点的预测误差给予更多的关注。

掩码(mask):
该类可以接受一个掩码 mask,指定哪些数据点应被纳入损失计算。这在处理缺失数据或不完整数据集时非常有用。

自定义功能:
由于继承自 BasePointLoss,这个 MAE 类可以进一步扩展和定制,以满足特定的需求。
示例实现中 _compute_weights 方法展示了如何计算权重,并在计算损失时使用这些权重。

具体示例比较

from typing import Optional, Union, Tuple
import math
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as Fdef _divide_no_nan(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:"""Auxiliary funtion to handle divide by 0"""div = a / bdiv[div != div] = 0.0div[div == float("inf")] = 0.0return div
def _weighted_mean(losses, weights):"""Compute weighted mean of losses per datapoint."""return _divide_no_nan(torch.sum(losses * weights), torch.sum(weights))
class BasePointLoss(torch.nn.Module):def __init__(self, horizon_weight, outputsize_multiplier, output_names):super(BasePointLoss, self).__init__()if horizon_weight is not None:horizon_weight = torch.Tensor(horizon_weight.flatten())self.horizon_weight = horizon_weightself.outputsize_multiplier = outputsize_multiplierself.output_names = output_namesself.is_distribution_output = Falsedef domain_map(self, y_hat: torch.Tensor):return y_hat.squeeze(-1)def _compute_weights(self, y, mask):if mask is None:mask = torch.ones_like(y, device=y.device)if self.horizon_weight is None:self.horizon_weight = torch.ones(mask.shape[-1])else:assert mask.shape[-1] == len(self.horizon_weight), "horizon_weight must have same length as Y"weights = self.horizon_weight.clone()weights = torch.ones_like(mask, device=mask.device) * weights.to(mask.device)return weights * maskclass MAE(BasePointLoss):"""Mean Absolute Error"""def __init__(self, horizon_weight=None):super(MAE, self).__init__(horizon_weight=horizon_weight, outputsize_multiplier=1, output_names=[""])def __call__(self,y: torch.Tensor,y_hat: torch.Tensor,mask: Union[torch.Tensor, None] = None,):losses = torch.abs(y - y_hat)weights = self._compute_weights(y=y, mask=mask)return _weighted_mean(losses=losses, weights=weights)# Example usage of custom MAE
mae_loss = MAE(horizon_weight=torch.tensor([1, 2, 3]))  # Custom weights for a 3-step horizon# 生成示例数据
batch_size = 2
horizon = 3# 随机生成输入数据和真实标签
y = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
y_hat = torch.tensor([[1.5, 2.5, 3.5], [4.5, 5.5, 6.5]])
mask = torch.tensor([[1, 0, 1], [1, 1, 1]])  # Consider some elements# 调用损失函数
loss = mae_loss(y, y_hat, mask=mask)# 打印 MAE 值
print("Mean Absolute Error (MAE):", loss.item())#Mean Absolute Error (MAE): 0.5

如果只是需要简单的 MAE,nn.L1Loss 就足够了;如果需要更多的控制和定制化,使用自定义的MAE(BasePointLoss)

这篇关于NeuralForecast VanillaTransformer MAE损失函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1034330

相关文章

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

Unity3D 运动之Move函数和translate

CharacterController.Move 移动 function Move (motion : Vector3) : CollisionFlags Description描述 A more complex move function taking absolute movement deltas. 一个更加复杂的运动函数,每次都绝对运动。 Attempts to

SigLIP——采用sigmoid损失的图文预训练方式

SigLIP——采用sigmoid损失的图文预训练方式 FesianXu 20240825 at Wechat Search Team 前言 CLIP中的infoNCE损失是一种对比性损失,在SigLIP这个工作中,作者提出采用非对比性的sigmoid损失,能够更高效地进行图文预训练,本文进行介绍。如有谬误请见谅并联系指出,本文遵守CC 4.0 BY-SA版权协议,转载请联系作者并注

✨机器学习笔记(二)—— 线性回归、代价函数、梯度下降

1️⃣线性回归(linear regression) f w , b ( x ) = w x + b f_{w,b}(x) = wx + b fw,b​(x)=wx+b 🎈A linear regression model predicting house prices: 如图是机器学习通过监督学习运用线性回归模型来预测房价的例子,当房屋大小为1250 f e e t 2 feet^

JavaSE(十三)——函数式编程(Lambda表达式、方法引用、Stream流)

函数式编程 函数式编程 是 Java 8 引入的一个重要特性,它允许开发者以函数作为一等公民(first-class citizens)的方式编程,即函数可以作为参数传递给其他函数,也可以作为返回值。 这极大地提高了代码的可读性、可维护性和复用性。函数式编程的核心概念包括高阶函数、Lambda 表达式、函数式接口、流(Streams)和 Optional 类等。 函数式编程的核心是Lambda

PHP APC缓存函数使用教程

APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”。它为我们提供了缓存和优化PHP的中间代码的框架。 APC的缓存分两部分:系统缓存和用户数据缓存。(Linux APC扩展安装) 系统缓存 它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存 3600s(一小时)。但是这样仍会浪费大量C