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=1k?xi+j?1??wj?

對于每一個輸出位置 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= ?x1?x2?x3??xn?k+1??x2?x3?x4??xn?k+2??x3?x4?x5??xn?k+3????xk?xk+1?xk+2??xn?? ?
然后將卷積核 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= ?w1?w2?w3??wk?? ?
那么,1維卷積的輸出可以表示為:
y = X ? w \mathbf{y} = \mathbf{X} \cdot \mathbf{w} y=X?w

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= ?123?234?345? ?
然后進行矩陣乘法:
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=X?w= ?123?234?345? ?? ?10?1? ?= ?1?1+2?0+3?(?1)2?1+3?0+4?(?1)3?1+4?0+5?(?1)? ?= ??2?2?2? ?
這就是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.pswp.cn/web/22780.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/22780.shtml
英文地址,請注明出處:http://en.pswp.cn/web/22780.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++模板類與Java泛型類的實戰應用及對比分析

C模板類和Java泛型類都是用于實現代碼重用和類型安全性的重要工具&#xff0c;但它們在實現方式和應用上有一些明顯的區別。下面&#xff0c;我將先分別介紹它們的實戰應用&#xff0c;然后進行對比分析。 C模板類的實戰應用 C模板類允許你定義一種通用的類&#xff0c;其中類…

SEO 與 PPC 之間的區別

按點擊付費 &#xff08;PPC&#xff09;&#xff1a; PPC 是一種網絡營銷技術&#xff0c;廣告商在每次點擊廣告時向網站支付一定金額&#xff0c;廣告商只為符合條件的點擊付費。Google 廣告、Bing 和 Yahoo 廣告基于按點擊付費的概念。PPC是用于在搜索引擎首頁上列出的最快方…

【前端】響應式布局筆記——rem

三、rem 指相對于根元素的字體大小的單位。 根字體大小通常設置為10px,方便換算。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-s…

鴻蒙開發接口安全:【@system.cipher (加密算法)】

加密算法 說明&#xff1a; 本模塊首批接口從API version 3開始支持。后續版本的新增接口&#xff0c;采用上角標單獨標記接口的起始版本。 導入模塊 import cipher from system.ciphercipher.rsa rsa(Object): void RSA 算法加解密。 系統能力&#xff1a; SystemCapabil…

Pointnet++改進卷積系列:全網首發SMPConv連續卷積 |即插即用,提升特征提取模塊性能

簡介:1.該教程提供大量的首發改進的方式,降低上手難度,多種結構改進,助力尋找創新點!2.本篇文章對Pointnet++特征提取模塊進行改進,加入SMPConv,提升性能。3.專欄持續更新,緊隨最新的研究內容。 目錄 1.理論介紹 2.修改步驟 2.1 步驟一 2.2 步驟二 2.3 步驟

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…

054、Python 函數的概念以及定義

編程大師Martin Fowler曾說過&#xff1a;“代碼有很多種壞味道&#xff0c;重復是最壞的一種。” 那么遇到重復的代碼&#xff0c;如何做&#xff1f;答案就是&#xff1a;函數。 函數就是把重復的代碼封裝在一起&#xff0c;然后通過調用該函數從而實現在不同地方運行同樣的…

解決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. 于是按…

蘋果ios用戶下載ipa文件內測簽名的后的app應用下載安裝到手機圖標消失了是什么原因呢?

下載好的應用竟然找不到了&#xff1f;究竟有哪些原因呢&#xff1f;本篇文章將總結一些可能性&#xff01; 若你在蘋果設備上下載了一個應用程序&#xff0c;但它的圖標不見了&#xff0c;可能有以下幾種原因&#xff1a; 1. 刪除應用的時候出現彈窗如果你錯誤的點擊到了從…

EasyRecovery2024破解版本下載,電腦數據恢復新突破!

在當今數字化時代&#xff0c;數據安全和軟件版權已成為全球關注的熱點。EasyRecovery&#xff0c;作為一款廣受歡迎的數據恢復軟件&#xff0c;因其強大的數據恢復功能而深受用戶喜愛。然而&#xff0c;隨著“EasyRecovery2024 crack”關鍵詞的流行&#xff0c;我們不得不面對…

電子電氣架構 —— 刷寫模式:并行刷寫

電子電氣架構 —— 刷寫模式:并行刷寫 我是穿拖鞋的漢子,魔都中堅持長期主義的工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 人們會在生活中不斷攻擊你。他們的主要武器是向你灌輸對自己的懷疑:你的價值、你的能力、你的潛力。他們往往會將此…

【深度學習入門篇一】阿里云服務器(不需要配環境直接上手跟學代碼)

前言 博主剛剛開始學深度學習&#xff0c;配環境配的心力交瘁&#xff0c;一塌糊涂&#xff0c;不想配環境的剛入門的同伴們可以直接選擇阿里云服務器 阿里云天池實驗室&#xff0c;在入門階段跑個小項目完全沒有問題&#xff0c;不要自己傻傻的在那配環境配了半天還不匹配&a…

二叉樹的層序遍歷Ⅱ-力扣

很簡單的一道題&#xff0c;將前一道題的結果數組進行一次反轉即可。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(i…

【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;能源轉…