NeuralForecast TokenEmbedding 一维卷积 (Conv1d) 与矩阵乘法

NeuralForecast TokenEmbedding 一维卷积 (Conv1d) 与矩阵乘法

flyfish

TokenEmbedding中使用了一维卷积 (Conv1d)

TokenEmbedding 源码分析

在源码的基础上增加调用示例
下面会分析这段代码

import torch
import torch.nn as nn
class TokenEmbedding(nn.Module):def __init__(self, c_in, hidden_size):super(TokenEmbedding, self).__init__()padding = 1 if torch.__version__ >= "1.5.0" else 2self.tokenConv = nn.Conv1d(in_channels=c_in,out_channels=hidden_size,kernel_size=3,padding=padding,padding_mode="circular",bias=False,)for m in self.modules():if isinstance(m, nn.Conv1d):nn.init.kaiming_normal_(m.weight, mode="fan_in", nonlinearity="leaky_relu")def forward(self, x):x = self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2)return ximport torch# 创建 TokenEmbedding 实例
c_in = 10  # 输入通道数
hidden_size = 20  # 输出通道数
token_embedding = TokenEmbedding(c_in, hidden_size)# 创建输入数据
batch_size = 32
sequence_length = 100
input_features = 10
x = torch.randn(batch_size, sequence_length, input_features)  # 输入数据形状为 (batch_size, sequence_length, input_features)# 前向传播
output = token_embedding(x)# 输出结果
print("Output shape:", output.shape)  # 打印输出的形状
#Output shape: torch.Size([32, 100, 20])

TokenEmbedding类继承自nn.Module类,通过super().init()调用了父类nn.Module的__init__()方法,以执行nn.Module类中的初始化操作,确保TokenEmbedding类的实例在创建时也执行了nn.Module类的初始化

init_ 方法:
在初始化过程中,定义了一个一维卷积层 self.tokenConv。这个卷积层的输入通道数为 c_in,输出通道数为 hidden_size,卷积核大小为 3,填充模式为 “circular”,并且设置偏置为 False。在 PyTorch 的版本大于等于 1.5.0 时,设置填充为 1,否则设置填充为 2。然后通过循环遍历模型的所有模块,并对其中类型为 nn.Conv1d 的模块进行参数初始化,使用 Kaiming 初始化方法。

forward 方法:
将输入 x 进行形状变换,然后通过 self.tokenConv 进行一维卷积操作,并将结果进行转置,最后返回卷积操作的结果。

比较下不同的padding_mode

import torch
import torch.nn as nn# 定义输入序列
input_seq = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32).view(1, 1, -1)# 定义卷积层
conv_zero_padding = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, padding=1, padding_mode='zeros', bias=False)
conv_circular_padding = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, padding=1, padding_mode='circular', bias=False)# 手动设置卷积核为简单的平均操作
with torch.no_grad():conv_zero_padding.weight = nn.Parameter(torch.ones_like(conv_zero_padding.weight) / 3)conv_circular_padding.weight = nn.Parameter(torch.ones_like(conv_circular_padding.weight) / 3)# 进行卷积操作
output_zero_padding = conv_zero_padding(input_seq)
output_circular_padding = conv_circular_padding(input_seq)print("Input sequence:", input_seq)
print("Zero padding output:", output_zero_padding)
print("Circular padding output:", output_circular_padding)
Input sequence: tensor([[[1., 2., 3., 4., 5.]]])
Zero padding output: tensor([[[1., 2., 3., 4., 3.]]], grad_fn=<ConvolutionBackward0>)
Circular padding output: tensor([[[2.6667, 2.0000, 3.0000, 4.0000, 3.3333]]],grad_fn=<ConvolutionBackward0>)

嵌入层 nn.Conv1d和 nn.Embedding不同的处理方式

使用 nn.Conv1d 的 TokenEmbedding

import torch
import torch.nn as nnclass TokenEmbedding(nn.Module):def __init__(self, c_in, hidden_size):super(TokenEmbedding, self).__init__()self.tokenConv = nn.Conv1d(in_channels=c_in,out_channels=hidden_size,kernel_size=3,padding=1,padding_mode="circular",bias=False,)def forward(self, x):x = self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2)return x# 示例输入
batch_size = 2
sequence_length = 10
feature_dim = 3time_series = torch.randn(batch_size, sequence_length, feature_dim)
embedding = TokenEmbedding(c_in=feature_dim, hidden_size=8)
embedded_time_series = embedding(time_series)
print(embedded_time_series.shape)  # 输出形状:[2, 10, 8]

使用 nn.Embedding

class SimpleEmbedding(nn.Module):def __init__(self, num_embeddings, embedding_dim):super(SimpleEmbedding, self).__init__()self.embedding = nn.Embedding(num_embeddings, embedding_dim)def forward(self, x):return self.embedding(x)# 示例输入:假设我们有一些离散的索引序列
batch_size = 2
sequence_length = 10
vocab_size = 20  # 假设有20个不同的类别
embedding_dim = 8indices = torch.randint(0, vocab_size, (batch_size, sequence_length))
embedding = SimpleEmbedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)
embedded_indices = embedding(indices)
print(embedded_indices.shape)  # 输出形状:[2, 10, 8]

Conv1d

(1维卷积)和矩阵乘法在数学上有密切的关系。1维卷积操作实际上可以看作是某种形式的矩阵乘法
1维卷积操作可以通过将输入向量转换成Toeplitz矩阵,然后与卷积核进行矩阵乘法来实现。这种方法可以帮助我们更好地理解卷积操作的本质及其与线性代数的关系。

1. Conv1d 操作

假设我们有一个输入向量 x = [ x 1 , x 2 , … , x n ] \mathbf{x} = [x_1, x_2, \ldots, x_n] x=[x1,x2,,xn] 和一个卷积核(滤波器) w = [ w 1 , w 2 , … , w k ] \mathbf{w} = [w_1, w_2, \ldots, w_k] w=[w1,w2,,wk],1维卷积操作可以定义为:

y i = ∑ j = 1 k x i + j − 1 ⋅ w j y_i = \sum_{j=1}^{k} x_{i+j-1} \cdot w_j yi=j=1kxi+j1wj

对于每一个输出位置 i i i,卷积核 w \mathbf{w} w 会与输入向量 x \mathbf{x} x 的某一部分元素进行点积。

2. 矩阵乘法表示

1维卷积操作可以通过将输入向量转换成一个特定的矩阵,然后进行矩阵乘法来实现。这种矩阵称为“Toeplitz矩阵”或“卷积矩阵”。例如,对于输入向量 x \mathbf{x} x 和卷积核 w \mathbf{w} w,我们构建一个Toeplitz矩阵:
X = [ x 1 x 2 x 3 … x k x 2 x 3 x 4 … x k + 1 x 3 x 4 x 5 … x k + 2 ⋮ ⋮ ⋮ ⋱ ⋮ x n − k + 1 x n − k + 2 x n − k + 3 … x n ] \mathbf{X} = \begin{bmatrix} x_1 & x_2 & x_3 & \ldots & x_k \\ x_2 & x_3 & x_4 & \ldots & x_{k+1} \\ x_3 & x_4 & x_5 & \ldots & x_{k+2} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ x_{n-k+1} & x_{n-k+2} & x_{n-k+3} & \ldots & x_n \end{bmatrix} X= x1x2x3xnk+1x2x3x4xnk+2x3x4x5xnk+3xkxk+1xk+2xn
然后将卷积核 w \mathbf{w} w 看作一个列向量:
w = [ w 1 w 2 w 3 ⋮ w k ] \mathbf{w} = \begin{bmatrix} w_1 \\ w_2 \\ w_3 \\ \vdots \\ w_k \end{bmatrix} w= w1w2w3wk
那么,1维卷积的输出可以表示为:
y = X ⋅ w \mathbf{y} = \mathbf{X} \cdot \mathbf{w} y=Xw

3. 示例

假设输入向量 x = [ 1 , 2 , 3 , 4 , 5 ] \mathbf{x} = [1, 2, 3, 4, 5] x=[1,2,3,4,5] 和卷积核 w = [ 1 , 0 , − 1 ] \mathbf{w} = [1, 0, -1] w=[1,0,1],我们可以构建Toeplitz矩阵:
X = [ 1 2 3 2 3 4 3 4 5 ] \mathbf{X} = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 3 & 4 & 5 \end{bmatrix} X= 123234345
然后进行矩阵乘法:
y = X ⋅ w = [ 1 2 3 2 3 4 3 4 5 ] ⋅ [ 1 0 − 1 ] = [ 1 ⋅ 1 + 2 ⋅ 0 + 3 ⋅ ( − 1 ) 2 ⋅ 1 + 3 ⋅ 0 + 4 ⋅ ( − 1 ) 3 ⋅ 1 + 4 ⋅ 0 + 5 ⋅ ( − 1 ) ] = [ − 2 − 2 − 2 ] \mathbf{y} = \mathbf{X} \cdot \mathbf{w} = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 3 & 4 & 5 \end{bmatrix} \cdot \begin{bmatrix} 1 \\ 0 \\ -1 \end{bmatrix} = \begin{bmatrix} 1 \cdot 1 + 2 \cdot 0 + 3 \cdot (-1) \\ 2 \cdot 1 + 3 \cdot 0 + 4 \cdot (-1) \\ 3 \cdot 1 + 4 \cdot 0 + 5 \cdot (-1) \end{bmatrix} = \begin{bmatrix} -2 \\ -2 \\ -2 \end{bmatrix} y=Xw= 123234345 101 = 11+20+3(1)21+30+4(1)31+40+5(1) = 222
这就是1维卷积的输出。
用代码演示一维卷积 (Conv1d) 和矩阵乘法会得到相同结果的方式

import torch
import torch.nn as nn# 输入序列
x = torch.tensor([[1, 2, 3, 4, 5]], dtype=torch.float32)  # shape: [1, 5]
# 卷积核
w = torch.tensor([[1, 0, -1]], dtype=torch.float32).unsqueeze(0)  # shape: [1, 3]# 使用 nn.Conv1d
conv1d = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, padding=0, bias=False)
conv1d.weight.data = wx_unsqueezed = x.unsqueeze(0)  # shape: [1, 1, 5]
output_conv1d = conv1d(x_unsqueezed).squeeze(0)  # shape: [1, 3]
print("Conv1d output:", output_conv1d)# 使用矩阵乘法
X = torch.tensor([[1, 2, 3],[2, 3, 4],[3, 4, 5]
], dtype=torch.float32)W = torch.tensor([1, 0, -1], dtype=torch.float32).view(-1, 1)output_matmul = X @ W
print("Matrix multiplication output:", output_matmul.squeeze())# Conv1d output: tensor([[-2., -2., -2.]], grad_fn=<SqueezeBackward1>)
# Matrix multiplication output: tensor([-2., -2., -2.])

在代码中,以下部分对卷积层的权重进行了初始化:

for m in self.modules():if isinstance(m, nn.Conv1d):nn.init.kaiming_normal_(m.weight, mode="fan_in", nonlinearity="leaky_relu")

这段代码使用了Kaiming初始化(也称为He初始化)来初始化卷积层的权重。为了理解为什么要使用 mode=“fan_in” 和 nonlinearity=“leaky_relu”,我们需要了解一些背景知识。

1. Kaiming 初始化 (He Initialization)

Kaiming初始化是一种针对神经网络权重的初始化方法,旨在解决在训练深度神经网络时可能遇到的梯度消失或梯度爆炸问题。Kaiming初始化的方法依据权重矩阵的大小来设置初始值,使得每一层的输出保持适当的方差。

2. mode=“fan_in” 和 nonlinearity=“leaky_relu”

  • mode=“fan_in”:这是Kaiming初始化中的一种模式,表示初始化应该考虑输入的数量(即每个神经元输入连接的数量)。使用这种模式,可以确保前向传播过程中信号的方差不会膨胀。
  • nonlinearity=“leaky_relu”:这是Kaiming初始化时需要指定的非线性激活函数类型。在初始化过程中,不同的激活函数需要不同的方差调整。leaky_relu 是一种变体的ReLU激活函数,可以防止神经元死亡问题。

详细解释

在使用Kaiming初始化时,根据不同的激活函数,初始化权重时需要调整标准差。Kaiming初始化的公式通常是:

std = 2 fan_in \text{std} = \sqrt{\frac{2}{\text{fan\_in}}} std=fan_in2

其中,fan_in 是指每个神经元输入的数量。

当使用不同的激活函数时,初始化的标准差需要调整,以适应激活函数的特点。对于ReLU和其变体(如Leaky ReLU),公式中的系数2是经验上获得的最优值。

因此,代码中指定 mode=“fan_in” 和 nonlinearity=“leaky_relu” 是为了确保在使用Leaky ReLU激活函数时,权重初始化的方差被正确地设置,从而使网络训练更加稳定和高效。

代码示例

具体到代码:

for m in self.modules():if isinstance(m, nn.Conv1d):nn.init.kaiming_normal_(m.weight, mode="fan_in", nonlinearity="leaky_relu")

这段代码的作用是遍历所有模块(即网络层),并对所有 nn.Conv1d 层的权重使用Kaiming初始化方法进行初始化。mode=“fan_in” 和 nonlinearity=“leaky_relu” 的指定,确保了权重的初始化是根据Leaky ReLU激活函数的特点来进行的。

Leaky ReLU

ReLU 函数将所有负值映射为零,正值不变。
Leaky ReLU 函数在负值区域有一个小的斜率(在此例子中为0.1),以避免神经元死亡。
PReLU 是Leaky ReLU的参数化版本,其负值区域的斜率可以学习。
ELU 在负值区域逐渐趋于一个负的固定值,正值区域类似ReLU。
在这里插入图片描述

import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F# 定义x轴数据
x = np.linspace(-10, 10, 400)
x_tensor = torch.tensor(x, dtype=torch.float32)# 定义不同的激活函数
relu = F.relu(x_tensor).numpy()
leaky_relu = F.leaky_relu(x_tensor, negative_slope=0.1).numpy()
prelu = torch.nn.PReLU(num_parameters=1, init=0.1)
prelu_output = prelu(x_tensor).detach().numpy()
elu = F.elu(x_tensor, alpha=1.0).numpy()# 绘图
plt.figure(figsize=(12, 8))plt.subplot(2, 2, 1)
plt.plot(x, relu, label='ReLU', color='blue')
plt.title('ReLU')
plt.grid(True)plt.subplot(2, 2, 2)
plt.plot(x, leaky_relu, label='Leaky ReLU (0.1)', color='red')
plt.title('Leaky ReLU')
plt.grid(True)plt.subplot(2, 2, 3)
plt.plot(x, prelu_output, label='PReLU (0.1)', color='green')
plt.title('PReLU')
plt.grid(True)plt.subplot(2, 2, 4)
plt.plot(x, elu, label='ELU', color='purple')
plt.title('ELU')
plt.grid(True)plt.tight_layout()
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/22780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SEO 与 PPC 之间的区别

按点击付费 &#xff08;PPC&#xff09;&#xff1a; PPC 是一种网络营销技术&#xff0c;广告商在每次点击广告时向网站支付一定金额&#xff0c;广告商只为符合条件的点击付费。Google 广告、Bing 和 Yahoo 广告基于按点击付费的概念。PPC是用于在搜索引擎首页上列出的最快方…

鸿蒙开发接口安全:【@system.cipher (加密算法)】

加密算法 说明&#xff1a; 本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import cipher from system.ciphercipher.rsa rsa(Object): void RSA 算法加解密。 系统能力&#xff1a; SystemCapabil…

K8S==ingress配置自签名证书

安装openssl Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 生成证书 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example.local.key -out example.local.crt -subj "/CNexample.local/Oexample.local"创建K8S secr…

【简单讲解TalkingData的数据统计】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Vue3中的常见组件通信之mitt

Vue3中的常见组件通信之mitt 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs…

用例篇03

正交表 因素&#xff1a;存在的条件 水平&#xff1a;因素的取值 最简单的正交表&#xff1a;L4(2) 应用 allpairs 来实现正交表。 步骤&#xff1a; 1.根据需求找出因素和水平 2.将因素和水平写入到excel表格中&#xff08;表格不需要保存&#xff09;&#xff08;推荐用…

SpaceX 首席火箭着陆工程师 MIT论文详解:非凸软着陆最优控制问题的控制边界和指向约束的无损凸化

上一篇blog翻译了 Lars Blackmore(Lars Blackmore is principal rocket landing engineer at SpaceX)的文章&#xff0c;SpaceX 使用 CVXGEN 生成定制飞行代码,实现超高速机载凸优化。利用地形相对导航实现了数十米量级的导航精度,着陆器在着陆过程中成像行星表面并将特征与机载…

PHP序列化、反序列化

目录 一、PHP序列化&#xff1a;serialize() 1.对象序列化 2.pop链序列化 3.数组序列化 二、反序列化&#xff1a;unserialize() 三、魔术方法 ​四、NSSCTF相关简单题目 1.[SWPUCTF 2021 新生赛]ez_unserialize 2.[SWPUCTF 2021 新生赛]no_wakeup 学习参考&#xff1…

解决MAC M1 Docker Desktop启动一直在starting

问题描述&#xff1a; 今天使用docker buildx 构建Multi-platform&#xff0c;提示如下错误&#xff1a; ERROR: Multi-platform build is not supported for the docker driver. Switch to a different driver, or turn on the containerd image store, and try again. 于是按…

EasyRecovery2024破解版本下载,电脑数据恢复新突破!

在当今数字化时代&#xff0c;数据安全和软件版权已成为全球关注的热点。EasyRecovery&#xff0c;作为一款广受欢迎的数据恢复软件&#xff0c;因其强大的数据恢复功能而深受用户喜爱。然而&#xff0c;随着“EasyRecovery2024 crack”关键词的流行&#xff0c;我们不得不面对…

电子电气架构 —— 刷写模式:并行刷写

电子电气架构 —— 刷写模式:并行刷写 我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人们会在生活中不断攻击你。他们的主要武器是向你灌输对自己的怀疑:你的价值、你的能力、你的潜力。他们往往会将此…

【深度学习入门篇一】阿里云服务器(不需要配环境直接上手跟学代码)

前言 博主刚刚开始学深度学习&#xff0c;配环境配的心力交瘁&#xff0c;一塌糊涂&#xff0c;不想配环境的刚入门的同伴们可以直接选择阿里云服务器 阿里云天池实验室&#xff0c;在入门阶段跑个小项目完全没有问题&#xff0c;不要自己傻傻的在那配环境配了半天还不匹配&a…

【ARM Cache 系列文章 2.1 -- Cache PoP 及 PoDP 介绍】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 PoP 及 PoDPCache PoDPCache PoP应用和影响PoP 及 PoDP Cache PoDP 点对深度持久性(Point of Deep Persistence, PoDP)是内存系统中的一个点,在该点达到的任何写操作即使在系统供电…

石油行业的数字化转型与智能化发展:新技术综合运用助力业务提升

引言 石油行业面临的挑战与机遇 石油行业是全球能源供应的重要支柱&#xff0c;然而&#xff0c;随着资源枯竭、环境压力增加以及市场竞争加剧&#xff0c;石油企业面临着前所未有的挑战。传统的勘探和生产方式已经难以满足当前高效、安全、环保的要求。同时&#xff0c;能源转…

用幻灯片来解释C/C++指针及运算

在互联网上发现了一个很好的C入门学习网站&#xff0c;用各种图表和幻灯片来学习C知识&#xff0c;非常直观&#xff0c;一目了然&#xff0c;比看文字更容易理解。做个搬运工用中文分享一下C/C最难懂的的内存指针的讲解&#xff0c;由浅入深的将指针解释的很清楚易懂&#xff…

web刷题记录(3)

[NISACTF 2022]checkin 简单的get传参,好久没做过这么简单的题了 王德发&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff01;&#xff0c;看了源代码以后&#xff0c;本来以为是js脚本的问题&#xff0c;但是禁用js脚本没用&#xff0c;看了大佬的wp以后…

鸿蒙轻内核M核源码分析系列六 任务及任务调度(2)任务模块

任务是操作系统一个重要的概念&#xff0c;是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源&#xff0c;并独立于其它任务运行。鸿蒙轻内核的任务模块可以给用户提供多个任务&#xff0c;实现任务间的切换&#xff0c;帮助用户管理业务程序流程。…

智慧校园究竟有何魅力?

随着科技的快速发展&#xff0c;智慧校园已成为教育领域的热门话题。智慧校园利用先进的技术手段&#xff0c;将信息化与教育深度融合&#xff0c;为学生、教师和家长提供更便捷、高效的教育服务。本文将带您深入了解智慧校园的魅力&#xff0c;让您对未来教育的发展充满期待。…

Ego微商项目部署(小程序项目)(全网最详细教程)

目录 1.项目部署前的准备 1.1获取APPID和APPSecret&#xff08;微信小程序&#xff09; 1.2测试工具 1.3微信开发者工具下载与安装 2.Ego微商后端项目部署 2.1部署细节流程 2.2部署架构图 2.3组件要求及版本 2.4后台部署操作 2.4.1安装vm和cenos7 2.4.2本地服务检查…

我们如何利用 0 美元营销将 UX/UI 产品发展到 320k 用户

嘿 &#x1f44b; 我是 Paul&#xff0c;FlowMapp 的联合创始人。 现在&#xff0c;我们是一个由7人&#xff08;少数兼职成员&#xff09;组成的团队&#xff0c;试图将产品扩展到$ 1M ARR。 希望这些对您有所帮助&#xff0c;并祝您未来的产品好运&#xff01; 我决定与…