51c深度學習~合集9

我自己的原文哦~??https://blog.51cto.com/whaosoft/12750420

#傅里葉特征 (Fourier Feature)與核回歸

位置編碼背后的理論解釋

本文探討了位置編碼背后的理論基礎,特別是傅里葉特征(Fourier Feature)與核回歸(Kernel Regression)的聯系,并解釋了如何通過這些理論來增強神經網絡對高頻信息的學習能力。

最近我在看位置編碼最新技術時,看到了一個叫做 "NTK-aware" 的詞。我想:「"NTK"是什么?Next ToKen (下一個詞元)嗎?為什么要用這么時髦的縮寫?」看著看著,我才發現不對勁。原來,NTK 是神經網絡理論里的一個概念,它從 kernel regression 的角度解釋了神經網絡的學習方法。基于 NTK 理論,有人解釋了位置編碼的理論原理并將其歸納為一種特殊的 Fourier Feature (傅里葉特征)。這么多專有名詞一下就把我繞暈了,我花了幾天才把它們之間的關系搞懂。

在這篇文章里,我主要基于論文_Fourier Features Let Networks Learn High Frequency Functions in Low Dimensional Domains_ (后文簡稱為「傅里葉特征論文」),介紹傅里葉特征這一概念。為了講清這些理論的發展脈絡,我會稍微講一下 NTK 等理論概念。介紹完傅里葉特征后,我還會講解它在其他方法中的應用。希望讀完本文后,讀者能夠以這篇論文為基點,建立一個有關位置編碼原理的知識網絡,以從更深的層次來思考新的科研方向。?

用 MLP 表示連續數據

我們先從一個具體的任務入手,直觀體會傅里葉特征能夠做些什么事。

我們知道,神經網絡,哪怕是最簡單的多層感知機(MLP),都有著很強的泛化能力:訓練完畢后,對于訓練集里完全沒見過的輸入,網絡也能給出很正確的輸出。特別地,如果新輸入恰好和訓練集的某個輸入很近,那么它的輸出也會和對應的訓練集輸出很近;隨著新輸出與訓練集輸入的距離不斷增加,新輸出也會逐漸變得不同。這反映了神經網絡的連續性:如果輸入的變化是連續的,那么輸出的變化也是連續的。

基于神經網絡的這一特性,有人想到:我們能不能用神經網絡來表示連續數據呢?比如我想表達一張處處連續的圖像,于是我令神經網絡的輸入是(x, y) 表示的二維坐標,輸出是 RGB 顏色。之后,我在單張圖像上過擬合這個 MLP。這樣,學會表示這張圖像后,哪怕輸入坐標是分數而不是整數,神經網絡也能給出一個顏色輸出。

這種連續數據有什么好處呢?我們知道,計算機都是以離散的形式來存儲數據的。比如,我們會把圖像拆成一個個像素,每個像素存在一塊內存里。對于圖像這種二維數據,計算機的存儲空間還勉強夠用。而如果想用密集的離散數據表達更復雜的數據,比如 3D 物體,計算機的容量就捉襟見肘了。但如果用一個 MLP 來表達 3D 物體的話,我們只需要存儲 MLP 的參數,就能獲取 3D 物體在任何位置的信息了。

這就是經典工作神經輻射場 (Neural Radiance Field, NeRF) 的設計初衷。NeRF 用一個 MLP 擬合 3D 物體的屬性,其輸入輸出如下圖所示。我們可以用 MLP 學習每個 3D 坐標的每個 2D 視角處的屬性(這篇文章用的屬性是顏色和密度)。根據這些信息,利用某些渲染算法,我們就能重建完整的 3D 物體。

圖片

上述過程看起來好像很簡單直接。但在 NeRF 中,有一個重要的實現細節:必須給輸入加上位置編碼,MLP 才能很好地過擬合連續數據。這是為什么呢?讓我們先用實驗復現一下這個現象。?

MLP 擬合連續圖像實驗

為了快速復現和位置編碼相關的問題,我們簡單地用一個 MLP 來表示圖像:MLP 的輸入是 2D 坐標,輸出是此處的三通道 RGB 顏色。我為這篇博文創建一個 GitHub 文件夾 https://github.com/SingleZombie/DL-Demos/tree/master/dldemos/FourierFeature ,該實驗的 Notebook 代碼在文件夾的??image_mlp.ipynb???中,歡迎大家 clone 項目并動手嘗試。

圖片

一開始,我們先導入庫并可視化要擬合的圖片。

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision.io import read_image, ImageReadMode
from torchvision.transforms.functional import to_pil_imagefrom tqdm import tqdm
from einops import rearrangedef viz_image(pt_img: torch.Tensor):pil_img = to_pil_image(pt_img)display(pil_img)input_image = read_image('misuzu.png', ImageReadMode.RGB)
input_image = input_image.to(torch.float32) / 255
input_image = input_image.unsqueeze(0)
input_image = F.interpolate(input_image, (256, 256), mode='bilinear')
viz_image(input_image[0])

圖片

我們再定義一個 MLP 類。稍后我們會并行地傳入二維坐標。具體來說,我們會將輸入定義為一個??[1, 2, H, W]????形狀的數據,其中通道數 2 表示??(i, j)???格式的坐標。由于輸入是以圖像的形式并行輸入的,我們可以用 的 2D 卷積來表示二維數據上的并行 MLP。所以在下面這個 MLP 里,我們只用到 卷積、激活函數、歸一化三種層。按照傅里葉特征論文的官方示例,網絡最后要用一個 Sigmoid 激活函數調整輸出的范圍。

class MLP(nn.Module):def __init__(self, in_c, out_c=3, hiden_states=256):super().__init__()self.mlp = nn.Sequential(nn.Conv2d(in_c, hiden_states, 1), nn.ReLU(), nn.BatchNorm2d(hiden_states),nn.Conv2d(hiden_states, hiden_states, 1), nn.ReLU(), nn.BatchNorm2d(hiden_states),nn.Conv2d(hiden_states, hiden_states, 1), nn.ReLU(), nn.BatchNorm2d(hiden_states),nn.Conv2d(hiden_states, out_c, 1), nn.Sigmoid())def forward(self, x):return self.mlp(x)

之后我們來定義訓練數據。在一般的任務中,輸入輸出都是從訓練集獲取的。而在這個任務中,輸入是二維坐標,輸出是圖像的顏色值。輸出圖像??input_image????我們剛剛已經讀取完畢了,現在只需要構建輸入坐標即可。我們可以用下面的代碼構建一個??[1, 2, H, W]????形狀的二維網格,??grid[0, :, i, j]????處的數據是其坐標??(i, j)????本身。當然,由于神經網絡的輸入一般要做歸一化,所以我們會把原本??0~H????和??0~W????里的高寬坐標縮放都到??0~1???。最終??grid[0, :, i, j]==(i/H, j/W)??。

H, W = input_image.shape[2:]h_coord = torch.linspace(0, 1, H)
w_coord = torch.linspace(0, 1, W)
grid = torch.stack(torch.meshgrid([h_coord, w_coord]), -1).permute(2, 0, 1).unsqueeze(0)

準備好一切后,我們就可以開始訓練了。我們初始化模型??model????和優化器??optimizer???,和往常一樣訓練這個 MLP。如前所述,這個任務的輸入輸出非常直接,輸入就是坐標網格??grid???,目標輸出就是圖片??input_image??。每訓練一段時間,我們就把當前 MLP 擬合出的圖片和誤差打印出來。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = MLP(2).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
n_loops = 400
input_image = input_image.to(device)
grid = grid.to(device)
for epoch in tqdm(range(n_loops)):output = model(grid)loss = F.l1_loss(output, input_image)optimizer.zero_grad()loss.backward()optimizer.step()if epoch % 100 == 0 or epoch == n_loops - 1:viz_image(output[0])print(loss.item())

運行代碼,大致能得到如下輸出。可以看到,從一開始,圖像就非常模糊。

圖片

不過,如果我們在把坐標輸入進網絡前先將其轉換成位置編碼——一種特殊的傅里葉特征,那么 MLP 就能清晰地擬合出原圖片。這里我們暫時不去關注這段代碼的實現細節。

class FourierFeature(nn.Module):def __init__(self, in_c, out_c, scale):super().__init__()fourier_basis = torch.randn(in_c, out_c // 2) * scaleself.register_buffer('_fourier_basis', fourier_basis)def forward(self, x):N, C, H, W = x.shapex = rearrange(x, 'n c h w -> (n h w) c')x = x @ self._fourier_basisx = rearrange(x, '(n h w) c -> n c h w', h = H, w = W)x = 2 * torch.pi * xx = torch.cat([torch.sin(x), torch.cos(x)], dim=1) return xfeature_length = 256
model = MLP(feature_length).to(device)
fourier_feature = FourierFeature(2, feature_length, 10).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
n_loops = 400
for epoch in tqdm(range(n_loops)):x = fourier_feature(grid)output = model(x)loss = F.l1_loss(output, input_image)optimizer.zero_grad()loss.backward()optimizer.step()if epoch % 100 == 0 or epoch == n_loops - 1:viz_image(output[0])print(loss.item())
prev_output = output

圖片

簡單地對比一下,此前方法的主要問題是 MLP 無法擬合高頻的信息(如圖塊邊緣),只能生成模糊的圖像。而使用位置編碼后,MLP 從一開始就能較好地表示高頻信息。可見,問題的關鍵在于如何讓 MLP 更好地擬合數據的高頻信息。

圖片

接下來,我們來從一個比較偏理論的角度看一看論文是怎么分析位置編碼在擬合高頻信息中的作用的。?

核回歸

傅里葉特征論文使用了神經正切核(Nerual Tangent Kernel, NTK)來分析 MLP 的學習規律,而 NTK 又是一種特殊的核回歸 (Kernel Regression) 方法。在這一節里,我會通過代碼來較為仔細地介紹核回歸。下一節我會簡單介紹 NTK。

和神經網絡類似,核回歸也是一種數學模型。給定訓練集里的輸入和輸出,我們建立這樣一個模型,用來擬合訓練集表示的未知函數。相比之下,核回歸的形式更加簡單,我們有更多的數學工具來分析其性質。

核回歸的設計思想來源于我們對于待擬合函數性質的觀察:正如我們在前文的分析一樣, 要用模型擬合一個函數時, 該模型在訓練數據附近最好是連續變化的。離訓練集輸入越近, 輸出就要和其對應輸出越近。基于這種想法,核回歸直接利用和所有數據的相似度來建立模型:假設訓練數據為?, 我們定義了一個計算兩個輸入相似度指標?, 那么任意輸入??的輸出為:

也就是說,對于一個新輸入??,我們算它和所有輸入??的相似度??,并把相似度歸一化。最后的輸出??是現有??的相似度加權和。

這樣看來,只要有了相似度指標,最終模型的形式也就決定下來了。我們把這個相似度指標稱為「核」。至于為什么要把它叫做核,是因為這個相似度指標必須滿足一些性質,比如非負、對稱。但我們這里不用管那么多,只需要知道核是一種衡量距離的指標,決定了核就決定了核回歸的形式。

我們來通過一個簡單的一維函數擬合實驗來進一步熟悉核回歸。該實驗代碼在項目文件夾下的??kernel_regression.ipynb???中。

先導入庫。

%matplotlib inlineimport numpy as np
import matplotlib.pyplot as plt

再創建一個簡單的非線性函數,做為我們的擬合目標。這個函數就是一個簡單的周期為 2 的正弦函數乘上線性函數??。我們可以簡單可視化一下函數在??之間的圖像。

def func(x):return np.sin(np.pi * x) * (1 - x)xs = np.linspace(-1, 1, 100)
ys = func(xs)
plt.plot(xs, ys)
plt.show()

圖片

基于這個函數,我們等間距地選一些點做為訓練數據。

sample_x = np.linspace(-1, 1, 10)
sample_y = func(sample_x)
plt.scatter(sample_x, sample_y)
plt.show()

圖片

有了數據后,我們來用核回歸根據數據擬合這個函數。在決定核回歸時,最重要的是決定核的形式。這里我們用正態分布的概率密度函數來表示核,該核唯一的超參數是標準差,需要我們根據擬合結果手動調整。標準差為??1???的標準正態分布核的圖像如下所示。由于最后要做歸一化,正態分布密度函數的系數被省略掉了。

def kernel_func(x_ref, x_input, sigma=1):return np.exp(-(x_input-x_ref)**2 / (2 * sigma**2))xs = np.linspace(-1, 1, 100)
ys = kernel_func(0, xs)
plt.plot(xs, ys)
plt.show()

圖片

可以從圖像中看出,離某輸入越近(假設該輸入是??0??),那么相似度就越高。這符合我們對于相似度函數的要求。

有了核函數后,我們就直接得到了模型。根據核回歸模型計算結果的函數為??kernel_regression???。函數參數??xs, ys????表示訓練數據,??x_input????表示測試時用的輸入坐標,??sigma???是核回歸的超參數。

假設有??n????個訓練樣本,有??m????個測試輸入,那么我們要計算每個測試輸入對每個訓練輸入的??n * m????個相似度,這些相似度會存到矩陣??weight????里。為此,我們需要對??xs????和??x_input????做一些形狀變換,再用上面定義的核函數??kernel_func????求出每對相似度。有了相似度后,我們根據公式計算點乘結果??weight_dot????及歸一化系數??weight_sum???,并最終計算出核回歸的結果??res??。

基于這個函數,我們可以將測試輸入定義成??[-1, 1]???上一些更密集的坐標,并用上面定義好的 10 個樣本做為訓練集,得到核回歸的結果。

def kernel_regression(xs, ys, x_input, sigma=1):# xs: [n, ]# ys: [n, ]# x_input: [m, ]N = xs.shape[0]xs = np.expand_dims(xs, 1)ys = np.expand_dims(ys, 1)x_input = np.expand_dims(x_input, 0)x_input = np.repeat(x_input, N, 0)weight = kernel_func(xs, x_input, sigma) # [n, m]weight_sum = np.sum(weight, 0)weight_dot = weight.T @ ysweight_dot = np.squeeze(weight_dot, 1)res = weight_dot / weight_sumreturn ressigma = 1
xs = np.linspace(-1, 1, 100)
ys = kernel_regression(sample_x, sample_y, xs, sigma)
plt.title(f'sigma = {sigma}')
plt.plot(xs, ys)
plt.show()

我們可以通過修改??sigma???來得到不同的擬合效果。以下是我的一些結果:

圖片

可以看出,標準差越小,模型傾向于過擬合;隨著標準差變大,曲線會逐漸平緩。我們需要不斷調整超參數,在過擬合和欠擬合之間找到一個平衡。這種現象很容易解釋:正態分布核函數的標準差越小,意味著每個訓練數據的影響范圍較小,那么測試樣本更容易受到少數樣本的影響;標準差增大之后,各個訓練樣本的影響開始共同起作用,我們擬合出的函數也越來越靠近正確的函數;但如果標準差過大,每個訓練樣本的影響都差不多,那么模型就什么都擬合不了了。

從實驗結果中,我們能大致感受到核回歸和低通濾波很像,都是將已知數據的平均效果施加在未知數據上。因此,在分析核回歸的時候,往往會從頻域分析核函數。如果核函數所代表低通濾波器的帶寬 (bandwidth)越大,那么剩下的高頻信息就更多,核回歸也更容易擬合高頻信息較多的數據。?

神經正切核

那么,核回歸是怎么和神經網絡關聯起來的呢?有研究表明,在一些特殊條件下,MLP 的最終優化結果可以用一個簡單的核回歸來表示。這不僅意味著我們可以神奇地提前預測梯度下降的結果,還可以根據核回歸的性質來分析神經網絡的部分原理。這種能表示神經網絡學習結果的核被稱為神經正切核(NTK)。

這些特殊條件包括 MLP 無限寬、SGD 學習率的學習率趨近 0 等。由于這些條件和實際神經網絡的配置相差較遠,我們難以直接用核回歸預測復雜神經網絡的結果。不過,我們依然可以基于這些理論來分析和神經網絡相關的問題。傅里葉特征的分析就是建立在 NTK 上的。

NTK 的形式為

圖片

其中,??是參數為??的神經網絡,??為內積運算。簡單來看, 這個式子是說神經網絡的核回歸中,任意兩個向量間的相似度等于網絡對參數的偏導的內積的期望。基于 NTK,我們可以分析出很多神經網絡的性質, 比如出乎意料地, 神經網絡的結果和隨機初始化的參數無關, 僅和網絡結構和訓練數據有關。

在學習傅里葉特征時, 我們不需要仔細研究這些這些理論, 而只需要知道一個結論: 一般上述 NTK 可以寫成標量函數?, 也就是可以先算內積再求偏導。這意味用核回歸表示神經網絡時, 真正要關心的是輸入間的內積。別看 NTK 看起來那么復雜, 傅里葉特征論文其實主要就用到了這一個性質。

為了從理論上講清為什么 MLP 難以擬合高頻,作者還提及了很多有關 NTK 的分析,包括一種叫做譜偏差(spectral bias)的現象:神經網絡更容易學習到數據中的低頻特征。可能作者默認讀者已經熟悉了相關的理論背景,這部分論述經常會出現邏輯跳躍,很難讀懂。當然,不懂這些理論不影響理解傅里葉特征。我建議不要去仔細閱讀這篇文章有關譜偏差的那一部分。

正如我們在前文的核回歸實驗里觀察到的,核回歸模型能否學到高頻取決于核函數的頻域特征。因此,這部分分析和 NTK 的頻域有關。對這部分內容感興趣的話可以去閱讀之前有關譜偏差的論文。

傅里葉特征的平移不變性

在上兩節中,我們花了不少功夫去認識譜回歸和 NTK。總結下來,其實我們只需要搞懂兩件事:

  • 神經網絡最終的收斂效果可以由簡單的核回歸決定。而核回歸重點是定義兩個輸入之間的相似度指標(核函數)。
  • 表示神經網絡的核回歸相似度指標是 NTK,它其實又只取決于兩個輸入的內積。

根據這一性質,我們可以部分解釋為什么在文章開頭那個 MLP 擬合連續圖像的實驗中,位置編碼可以提升 MLP 擬合高頻信息的能力了。這和位置輸入的特性有關。

當 MLP 的輸入表示位置時, 我們希望模型對輸入位置具有平移不變性。比如我們現在有一條三個樣本組成的句子??。當我們同時改變句子的位置信息時, 比如將句子的位置改成??時, 網絡能學出完全一樣的東西。但顯然不對輸入位置做任何處理的話,??和??對神經網絡來說是完全不同的意思。

而使用位置編碼的話,情況就完全不同了。假如輸入數據是二維坐標??,我們可以用下面的式子建立一個維度為??的位置編碼:

圖片

其中??是系數,??是一個投影矩陣, 用于把原來 2 D 的位置變成一個更長的位置編碼。當然, 由于位置編碼中既要有??也要有?, 所以最終的位置編碼長度為??。

根據我們之前的分析,NTK 只取決于輸入間的內積。算上位置編碼后,一對輸入位置?的內積為:

圖片

而根據三角函數和角公式可知:

圖片

這樣,上面那個內積恰好可以寫成:

圖片

上式完全由位置間的相對距離決定。上式決定了 NTK,NTK 又決定了神經網絡的學習結果。所以,神經網絡的收斂結果其實完全取決于輸入間的相對距離,而不取決于它們的絕對距離。也因此,位置編碼使得 MLP 對于輸入位置有了平移不變性。

加入位置編碼后,雖然 MLP 滿足了平移不變性,但這并不代表 MLP 學習高頻信息的能力就變強了。平移不變性能給我們帶來什么好處呢?作者指出,當滿足了平移不變性后,我們就能手動調整 NTK 的帶寬了。回想一下我們上面做的核回歸實驗,如果我們能夠調整核的帶寬,就能決定函數是更加高頻(尖銳)還是更加低頻(平滑)。這里也是同理,如果我們能夠調大 NTK 的帶寬,讓它保留更多高頻信息,那么 MLP 也就能學到更多的高頻信息。

作者在此處用信號處理的知識來分析平移不變性的好處,比如講了新的 NTK 就像一個重建卷積核 (reconstruction filter),整個 MLP 就像是在做卷積。還是由于作者省略了很多推導細節,這部分邏輯很難讀懂。我建議大家直接記住推理的結論:平移不變性使得我們能夠調整 NTK 的帶寬,從而調整 MLP 學習高頻的能力。

那我們該怎么調整 NTK 的帶寬呢?現在的新 NTK 由下面的式子決定:

圖片

為了方便分析, 我們假設??和??都是一維實數。那么, 如果我們令??的話:

圖片

這個式子能令你想到什么? 沒錯, 就是傅里葉變換。?較大的項就表示 NTK 的高頻分量。我們可以通過修改前面的系數??來手動調整 NTK 的頻域特征。我們能看到,位置編碼其實就是在模擬傅里葉變換,所以作者把位置編碼總結為傅里葉特征。

作者通過實驗證明我們可以手動修改 NTK 的頻譜。實驗中, 作者令??。?表示位置編碼只有第一項:?。不同??時 NTK 的空域和頻域示意圖如下所示。可以看出, 令??時, 即傅里葉特征所有項的系數都為 1 時, NTK 的高頻分量不會衰減。這也意味著 MLP 學高頻信息和低頻信息的能力差不多。

圖片

隨機傅里葉特征

現在我們已經知道傅里葉特征的公式是什么, 并知道如何設置其中的參數??了。現在, 還有一件事我們沒有決定:該如何設置傅里葉特征的長度??呢?

既然我們說傅里葉特征就是把輸入的位置做了一次傅里葉變換, 那么一般來講, 傅里葉特征的長度應該和原圖像的像素數一樣。比如我們要表示一個??的圖像, 那么我們就需要令??表示不同方向上的頻率:?。但這樣的話, 神經網絡的參數就太多了。可不可以令??更小一點呢?

根據之前的研究Random features for large-scale kernel machines 表明, 我們不需要密集地采樣傅里葉特征, 只需要稀疏地采樣就行了。具體來說, 我們可以從某個分布隨機采樣?個頻率??來, 這樣的學習結果和密集采樣差不多。當然, 根據前面的分析, 我們還是令所有系數??。在實驗中, 作者發現,??從哪種分布里采樣都無所謂, 關鍵是??的采樣分布的標準差, 因為這個標準差決定了傅里葉特征的帶寬, 也決定了網絡擬合高頻信息的能力。實驗的結果如下:

圖片

我們可以不管圖片里??是啥意思, 只需要知道??是三組不同的實驗就行。虛線是密集采樣傅里葉特征的誤差,它的結果反映了一個「較好」的誤差值。令人驚訝的是,不管從哪種分布里采樣?, 最后學出來的網絡誤差都差不多。問題的關鍵在于采樣分布的標準差。把標準差調得夠好的話, 模型的誤差甚至低于密集采樣的誤差。

也就是說,雖然我們花半天分析了位置編碼和傅里葉變換的關系,但我們沒必要照著傅里葉變換那樣密集地采樣頻率,只需要隨機選一些頻率即可。當然,這個結論只對 MLP 擬合連續數據的任務有效,和 Transformer 里的位置編碼無關。?

代碼實現隨機傅里葉特征

現在,我們可以回到博文開頭的代碼,看一下隨機傅里葉特征是怎么實現的。

class FourierFeature(nn.Module):def __init__(self, in_c, out_c, scale):super().__init__()fourier_basis = torch.randn(in_c, out_c // 2) * scaleself.register_buffer('_fourier_basis', fourier_basis)def forward(self, x):N, C, H, W = x.shapex = rearrange(x, 'n c h w -> (n h w) c')x = x @ self._fourier_basisx = rearrange(x, '(n h w) c -> n c h w', h = H, w = W)x = 2 * torch.pi * xx = torch.cat([torch.sin(x), torch.cos(x)], dim=1) return xfeature_length = 256
model = MLP(feature_length).to(device)
fourier_feature = FourierFeature(2, feature_length, 10).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
n_loops = 400
for epoch in tqdm(range(n_loops)):x = fourier_feature(grid)output = model(x)loss = F.l1_loss(output, input_image)optimizer.zero_grad()loss.backward()optimizer.step()if epoch % 100 == 0 or epoch == n_loops - 1:viz_image(output[0])print(loss.item())
prev_output = output

傅里葉特征通過類??FourierFeature???實現。其代碼如下:

class FourierFeature(nn.Module):def __init__(self, in_c, out_c, scale):super().__init__()fourier_basis = torch.randn(in_c, out_c // 2) * scaleself.register_buffer('_fourier_basis', fourier_basis)def forward(self, x):N, C, H, W = x.shapex = rearrange(x, 'n c h w -> (n h w) c')x = x @ self._fourier_basisx = rearrange(x, '(n h w) c -> n c h w', h = H, w = W)x = 2 * torch.pi * xx = torch.cat([torch.sin(x), torch.cos(x)], dim=1) return x

構造函數里的??fourier_basis????表示隨機傅里葉特征的頻率,對應論文公式里的,??scale????表示采樣的標準差。初始化好了隨機頻率后,對于輸入位置??x???,只要按照公式將其投影到長度為??out_c / 2????的向量上,再對向量的每一個分量求??sin, cos???即可。按照之前的分析,我們令所有系數 為,所以不需要對輸出向量乘系數。?

傅里葉特征在 StyleGAN3 里的應用

傅里葉特征最經典的應用就是 NeRF 這類過擬合連續數據任務。除此之外,傅里葉特征另一次大展身手是在 StyleGAN3 中。

StyleGAN3 希望通過平滑地移動生成網絡的輸入來使輸出圖片也發生對應的移動。為此,StyleGAN3 將生成網絡的輸入定義為頻域上的一個有限帶寬圖像信號:根據信號處理知識,我們能夠將有限帶寬信號轉換成空域上無限連續的信號。也就是說,不管輸入的分辨率(采樣率)多低,我們都能夠平滑地移動輸入圖片。StyleGAN3 借助隨機傅里葉特征來實現這樣一個頻域圖像。

以下代碼選自 StyleGAN3 中傅里葉特征的構造函數。這個函數的關鍵是隨機生成一些頻率固定,但方向可以不同的傅里葉頻率。函數先隨機采樣了一些頻率,再將它們歸一化,最后乘上指定的帶寬??bandwidth??,保證所有頻率大小相等。

class SynthesisInput(torch.nn.Module):def __init__(self,w_dim,          # Intermediate latent (W) dimensionality.channels,       # Number of output channels.size,           # Output spatial size: int or [width, height].sampling_rate,  # Output sampling rate.bandwidth,      # Output bandwidth.):super().__init__()self.w_dim = w_dimself.channels = channelsself.size = np.broadcast_to(np.asarray(size), [2])self.sampling_rate = sampling_rateself.bandwidth = bandwidth# Draw random frequencies from uniform 2D disc.freqs = torch.randn([self.channels, 2])radii = freqs.square().sum(dim=1, keepdim=True).sqrt()freqs /= radii * radii.square().exp().pow(0.25)freqs *= bandwidthphases = torch.rand([self.channels]) - 0.5

而在使用這個類獲取網絡輸入時,和剛剛的 MLP 實現一樣,我們會先生成一個二維坐標表格??grid???用于查詢連續圖片每一處的顏色值,再將其投影到各個頻率上,并計算新向量的正弦函數。

這段代碼中,有兩塊和我們自己的實現不太一樣。第一,StyleGAN3 允許對輸入坐標做仿射變換(平移和旋轉)。仿射變換對坐標的影響最終會轉化成對三角函數相位??phases????和頻率??freqs???的影響。第二,在計算三角函數時,StyleGAN3 只用了正弦函數,沒有用余弦函數。

def forward(self, ...):...# Transform frequencies.phases = ...freqs = ...# Construct sampling grid.theta = torch.eye(2, 3, device=w.device)theta[0, 0] = 0.5 * self.size[0] / self.sampling_ratetheta[1, 1] = 0.5 * self.size[1] / self.sampling_rategrids = torch.nn.functional.affine_grid(theta.unsqueeze(0), [1, 1, self.size[1], self.size[0]], align_corners=False)# Compute Fourier features.x = (grids.unsqueeze(3) @ freqs.permute(0, 2, 1).unsqueeze(1).unsqueeze(2)).squeeze(3) # [batch, height, width, channel]x = x + phases.unsqueeze(1).unsqueeze(2)x = torch.sin(x * (np.pi * 2))x = x * amplitudes.unsqueeze(1).unsqueeze(2)...# Ensure correct shape.x = x.permute(0, 3, 1, 2) # [batch, channel, height, width]return x

我們在 MLP 擬合連續圖像的實驗里復現一下這兩個改動。首先是二維仿射變換。給定旋轉角??theta????和兩個方向的平移??tx, ty???,我們能夠構造出一個 的仿射變換矩陣。把它乘上坐標??[x, y, 1]????后,就能得到仿射變換的輸出。我們對輸入坐標??grid????做仿射變換后得到??grid_ext???,再用??grid_ext???跑一遍傅里葉特征和 MLP。

N, C, H, W = grid.shape
tx = 50 / H
ty = 0
theta = torch.tensor(torch.pi * 1 / 8)
affine_matrix = torch.tensor([[torch.cos(theta), -torch.sin(theta), tx],[torch.sin(theta), torch.cos(theta), ty],[0, 0, 1]
]
).to(device)
grid_ext = torch.ones(N, 3, H, W).to(device)
grid_ext[:, :2] = grid.clone()
grid_ext = grid_ext.permute(0, 2, 3, 1)
grid_ext = (grid_ext @ affine_matrix.T)
grid_ext = grid_ext.permute(0, 3, 1, 2)[:, :2]x = fourier_feature(grid_ext)
output = model(x)
viz_image(output[0])

在示例代碼中,我們可以得到旋轉 45 度并向下平移 50 個像素的圖片。可以看到,變換成功了。這體現了連續數據的好處:我們可以在任意位置對數據采樣。當然,由于這種連續數據是通過過擬合實現的,在訓練集沒有覆蓋的坐標處無法得到有意義的顏色值。

圖片

之后,我們來嘗試在傅里葉特征中只用正弦函數。我們將投影矩陣的輸出通道數從??out_c / 2????變成??out_c???,再在??forward????里只用??sin????而不是同時用??sin, cos??。經實驗,這樣改了后完全不影響重建質量,甚至由于通道數更多了,重建效果更好了。

class FourierFeature(nn.Module):def __init__(self, in_c, out_c, scale):super().__init__()fourier_basis = torch.randn(in_c, out_c) * scaleself.register_buffer('_fourier_basis', fourier_basis)def forward(self, x):N, C, H, W = x.shapex = rearrange(x, 'n c h w -> (n h w) c')x = x @ self._fourier_basisx = rearrange(x, '(n h w) c -> n c h w', h = H, w = W)x = 2 * torch.pi * xx = torch.sin(x)return x

StyleGAN3 論文并沒有講為什么只用??sin??,網上也很少有人討論傅里葉特征的實現細節。我猜傅里葉特征并不是非得和傅里葉變換完全對應,畢竟它只是用來給神經網絡提供更多信息,而沒有什么嚴格的意義。只要把輸入坐標分解成不同頻率后,神經網絡就能很好地學習了。

只用??sin????而不是同時用??sin, cos????后,似乎我們之前對 NTK 平移不變的推導完全失效了。但是,根據三角函數的周期性可知,只要是把輸入映射到三角函數上后,網絡主要是從位置間的相對關系學東西。絕對位置對網絡來說沒有那么重要,不同的絕對位置只是讓所有三角函數差了一個相位而已。只用??sin????的神經網絡似乎也對絕對位置不敏感。為了證明這一點,我把原來位于??[0, 1]????間的坐標做了一個幅度為??10???的平移。結果網絡的誤差幾乎沒變。

for epoch in tqdm(range(n_loops)):x = fourier_feature(grid + 10)output = model2(x)loss = F.l1_loss(output, input_image)optimizer.zero_grad()loss.backward()optimizer.step()

根據這些實驗結果,我感覺是不是從 NTK 的角度來分析傅里葉特征完全沒有必要?是不是只要從直覺上理解傅里葉特征的作用就行了?按我的理解,傅里葉特征在真正意義在于顯式把網絡對于不同頻率的關注度建模出來,從而輔助網絡學習高頻細節。?

總結

在這篇博文中,我們學習了傅里葉特征及其應用,并順帶了解其背后有關核回歸、NTK 的有關理論知識。這些知識很雜亂,我來按邏輯順序把它們整理一下。

為了解釋為什么 NeRF 中的位置編碼有效,傅里葉特征論文研究了用 MLP 擬合連續數據這一類任務中如何讓 MLP 更好地學到高頻信息。論文有兩大主要結論:

  • 通過從 NTK 理論的分析,位置編碼其實是一種特殊的傅里葉特征。這種特征具有平移不變性。因此,神經網絡就像是在對某個輸入信號做卷積。而我們可以通過調整傅里葉特征的參數來調整卷積的帶寬,也就是調整網絡對于不同頻率的關注程度,從而使得網絡不會忽略高頻信息。
  • 傅里葉特征的頻率不需要密集采樣,只需要從任意一個分布隨機稀疏采樣。影響效果的關鍵是采樣分布的標準差,它決定了傅里葉特征的帶寬,也就決定了網絡是否能關注到高頻信息。

除了過擬合連續數據外,傅里葉特征的另一個作用是直接表示帶寬有限信號,以實現在空域上的連續采樣。StyleGAN3 在用傅里葉特征時,允許對輸入坐標進行仿射變換,并且計算特征時只用了正弦函數而不是同時用正弦、余弦函數。這表明有關 NTK 的理論分析可能是沒有必要的,主要說明問題的還是實驗結果。

傅里葉特征論文僅研究了擬合連續數據這一類問題,沒有討論 Transformer 中位置編碼的作用。論文中的一些結論可能無法適用。比如在大模型的位置編碼中,我們還是得用密集的sin, cos 變換來表示位置編碼。不過,我們可以依然借助該論文中提到的理論分析工具,來嘗試分析所有位置編碼的行為。

只通過文字理解可能還不太夠,歡迎大家嘗試我為這篇博客寫的 Notebook,通過動手做實驗來加深理解。https://github.com/SingleZombie/DL-Demos/tree/master/dldemos/FourierFeature

#讓模型預見分布漂移

動態系統顛覆性設計引領時域泛化新革命本研究提出了一種方法,能夠在領域數據分布持續變化的動態環境中,基于隨機時刻觀測的數據分布,在任意時刻生成適用的神經網絡。

下圖展示了模型在領域數據隨時間發生旋轉和膨脹時的泛化表現。通過在一些隨機時間點(藍色標記點)的觀測,模型可以在任意時刻生成適用的神經網絡,其決策邊界始終與數據分布保持協調一致。

圖片

01?摘要

在實際應用中,數據集的數據分布往往隨著時間而不斷變化,預測模型需要持續更新以保持準確性。時域泛化旨在預測未來數據分布,從而提前更新模型,使模型與數據同步變化。

然而,傳統方法假設領域數據在固定時間間隔內收集,忽視了現實任務中數據集采集的隨機性和不定時性,無法應對數據分布在連續時間上的變化。此外,傳統方法也難以保證泛化過程在整個時間流中保持穩定和可控。

為此,本文提出了連續時域泛化任務,并設計了一個基于模型動態系統的時域泛化框架 Koodos,使得模型在連續時間中與數據分布的變化始終保持協調一致。Koodos 通過庫普曼算子將模型的復雜非線性動態轉化為可學習的連續動態系統,同時利用先驗知識以確保泛化過程的穩定性和可控性。

實驗表明,Koodos 顯著超越現有方法,為時域泛化開辟了全新的研究方向。

02?論文信息

論文鏈接:?

??https://arxiv.org/pdf/2405.16075??

開源代碼:

??https://github.com/Zekun-Cai/Koodos/??

OpenReview:

??https://openreview.net/forum?id=G24fOpC3JE??

我們在代碼庫中提供了詳細的逐步教程,涵蓋了 Koodos 的實現、核心概念的解讀以及可視化演示:

??https://github.com/Zekun-Cai/Koodos/blob/main/Tutorial_for_Koodos.ipynb??

整個教程流程緊湊,十分鐘即可快使掌握 Koodos 的使用方法,力薦嘗試!

03?情景導入

在實際應用中,訓練數據的分布通常與測試數據不同,導致模型在訓練環境之外的泛化能力受限。領域泛化(Domain Generalization, DG)作為一種重要的機器學習策略,旨在學習一個能夠在未見目標領域中也保持良好表現的模型。

近年來研究人員發現,在動態環境中,領域數據(Domain Data)分布往往具有顯著的時間依賴性,這促使了時域泛化(Temporal Domain Generalization, TDG)技術的快速發展。

時域泛化將多個領域視為一個時間序列而非一組獨立的靜態個體,利用歷史領域預測未來領域,從而實現對模型參數的提前調整,顯著提升了傳統 DG 方法的效果。

然而,現有的時域泛化研究集中在“離散時間域”假設下,即假設領域數據在固定時間間隔(如逐周或逐年)收集。基于這一假設,概率模型被用于預測時域演變,例如通過隱變量模型生成未來數據,或利用序列模型(如 LSTM)預測未來的模型參數。

然而在現實中,領域數據的觀測并不總是在離散、規律的時間點上,而是隨機且稀疏地分布在連續時間軸上。例如,圖 1 展示了一個典型的例子——基于推文數據進行社交媒體輿情預測。

與傳統 TDG 假設的領域在時間軸上規律分布不同,實際中我們只能在特定事件(如總統辯論)發生時獲得一個域,而這些事件的發生時間并不固定。同時,概念漂移(Concept Drift)在時間軸上發生,即領域數據分布隨著時間不斷演變:如活躍用戶增加、新交互行為形成、年齡與性別分布變化等。

理想情況下,每個時態域對應的預測模型也應隨時間逐漸調整,以應對這種概念漂移。最后,由于未來的域采集時間未知,我們希望可以泛化預測模型到未來任意時刻。

圖片

▲?圖1:連續時域泛化示意圖。圖中展示了通過推文訓練分類模型進行輿情預測。其中訓練域僅能在特定政治事件(如總統辯論)前后采集。我們希望通過這些不規律時間分布的訓練域來捕捉分布漂移,并最終使模型能夠推廣到任意未來時刻。

事實上,領域分布在連續時間上的場景十分常見,例如:

事件驅動的數據采集:僅在特定事件發生時采集領域數據,事件之間沒有數據。

流數據的隨機觀測:領域數據在數據流的任意時間點開始或結束采集,而非持續進行。

離散時態域但缺失:盡管領域數據基于離散時間點采集,但部分時間節點的領域數據缺失。

為了應對這些場景中的模型泛化,我們提出了“連續時域泛化”(Continuous Temporal Domain Generalization, CTDG)任務,其中觀測和未觀測的領域均分布于連續時間軸上隨機的時間點。CTDG 關注于如何表征時態領域的連續動態,使得模型能夠在任意時間點實現穩定、適應性的調整,從而完成泛化預測

04?核心挑戰

CTDG 任務的挑戰遠超傳統的 TDG 方法。CTDG 不僅需要處理不規律時間分布的訓練域,更重要的是,它旨在讓模型泛化到任意時刻,即要求在連續時間的每個點上都能精確描述模型狀態。

而 TDG 方法則僅關注未來的單步泛化:在觀測點優化出當前模型狀態后,只需將其外推一步即可。這使得 CTDG 區別于 TDG 任務:CTDG 的關鍵在于如何在連續時間軸上同步數據分布和模型參數的動態演變,而不是僅局限于未來某一特定時刻的模型表現

具體而言,與 TDG 任務相比,CTDG 的復雜性主要來自以下幾個尚未被充分探索的核心挑戰:

如何建模數據動態并同步模型動態:CTDG 要求在連續時間軸上捕捉領域數據的動態,并據此同步調整模型狀態。然而,數據動態本身難以直接觀測,需要通過觀測時間點來學習。此外,模型動態的演變過程也同樣復雜。理解數據演變如何驅動模型演變構成了 CTDG 的首要挑戰。

如何在高度非線性模型動態中捕捉主動態:領域數據的預測模型通常依賴過參數化(over-parametrized)的深度神經網絡,模型動態因此呈現出高維、非線性的復雜特征。這導致模型的主動態嵌藏在大量潛在維度中。如何有效提取并將這些主動態映射到可學習的空間,是 CTDG 任務中的另一重大挑戰。

如何確保長期泛化的穩定性和可控性:為實現未來任意時刻的泛化,CTDG 必須確保模型的長期穩定性。此外,在許多情況下,我們可能擁有數據動態的高層次先驗知識。如何將這些先驗知識嵌入 CTDG 的優化過程中,進而提升泛化的穩定性和可控性,是一個重要的開放性問題。

05?技術方法

5.1 問題定義

在 CTDG 中,一個域??表示在時間??采集的數據集,由實例集??組成,其中??和??分別為特征值,目標值和實例數。我們重點關注連續時間上的漸進性概念漂移,表示為領域數據的條件概率分布??隨時間平滑變化。

在訓練階段,模型接收一系列在不規律時間點??上收集的觀測域??,其中每個時間點??是定義在連續時間軸?上的實數,且滿足 $t_1<t_2<\ldots<t_t$ 。<="" p="">

在每個??上,模型學習到領域數據??的預測函數??,其中??表示??時刻的模型參數。CTDG 的目標是建模參數的動態變化,以便在任意給定時刻??上預測模型參數??,從而得到泛化模型??。

在后續部分中,我們使用簡寫符號?、、?和??,分別表示在時間??上的?、?、??和??。

5.2 設計思路

我們的方法通過模型與數據的同步、動態簡化表示,以及高效的聯合優化展開。具體思路如下:

1.?同步數據和模型的動態:我們證明了連續時域中模型參數的連續性,而后借助神經微分方程(Neural ODE)建立模型動態系統,從而實現模型動態與數據動態的同步。

2.?表征高維動態到低維空間:我們將高維模型參數映射到一個結構化的庫普曼空間(Koopman Space)中。該空間通過可學習的低維線性動態來捕捉模型的主要動態。

3.?聯合優化模型與其動態:我們將單個領域的模型學習與各時間點上的連續動態進行聯合優化,并設計了歸納偏置的約束接口,通過端到端優化保證泛化的穩定性和可控性。

圖片

▲ 模型設計

5.3 解決方案

Step 1. 數據動態建模與模型動態同步

分布變化的連續性假設:我們首先假設數據分布在時間上具有連續演化的特性,即條件概率分布??隨時間平滑變化, 其演化規律可由一個函數??所描述的動態系統刻畫。盡管真實世界中的漸進概念漂移可能較為復雜,但因概念漂移通常源于底層的連續過程(如自然、生物、物理、社會或經濟因素),這一假設不失普適性。

分布變化引發的模型參數連續演化:基于上述假設,模型的函數功能空間應隨數據分布變化同步調整。我們借助常微分方程來描述這一過程:

圖片

由此可推導出模型參數的演化滿足:

圖片

其中,??是??對??的雅可比矩陣。

這一結果表明,如果數據分布的演化在時間上具有連續性,那么的演化過程也具有連續性,即模型參數會隨數據分布的變化而平滑調整。上式為建立了一個由微分方程描述的模型動態系統

模型動態系統學習:由于數據動態??的具體形式未知, 直接求解上述微分方程并不可行。為此, 我們引入一個由神經網絡定義的連續動態系統, 用可學習的函數??描述模型參數??的變化。

通過鼓勵模型動態和數據動態之間的拓撲共軛(Topological Conjugation)關系使??逼近真實動態。具體而言, 拓撲共軛要求通過泛化獲得的模型參數與直接訓練得到的參數保持一致。為此, 我們設定以下優化目標, 以學習??的參數??:

圖片

其中,??通過在時刻??的領域上直接訓練獲得,??則表示從時間??通過動態??演變至??的泛化參數:

圖片

通過這一優化過程,我們建立了模型動態與數據動態之間的同步機制。借助動態函數,我們可以在任意時刻精確求解模型的狀態。

Step 2. 通過庫普曼算子簡化模型動態

非線性動態線性化

在實際任務中, 預測模型通常依賴于過參數化的深度神經網絡, 使得模型動態??呈現為在高維空間中糾纏的非線性動態。直接對??建模不僅計算量大,且極易導致泛化不穩定。

然而,??受數據動態??的支配, 而數據動態通常是簡單、可預測的。這意味著在過參數化空間中,模型的主動態(Principal Dynamics)可以在適當轉換的空間內進行更易于管理的表示。

受此驅動,我們引入庫普曼理論(Koopman Theory)來簡化復雜的模型動態。庫普曼理論在保持動態系統特征的同時將復雜的非線性動態線性化。

具體而言, 我們定義一個庫普曼嵌入函數?, 將原始的高維參數空間映射到一個低維的庫普曼空間中:

圖片

其中,??表示庫普曼空間中的低維表示。通過庫普曼算子?, 我們可以在線性空間中刻畫?的動態:

圖片

一旦獲得了簡化的動態表示,我們可以在庫普曼空間中更新模型參數,而后將其反映射回原始參數空間:

圖片

最終,通過庫普曼算子的引入,我們實現了對模型動態的簡化,保證了泛化過程的穩健性。

Step 3. 聯合優化與先驗知識結合

模型及其動力學的聯合優化:我們對多個組件同時施加約束確保模型能穩定泛化,其包含以下關鍵項:

  • 預測準確性:通過最小化預測誤差,使預測模型在每個觀測時間點都能準確預測實際數據。
  • 泛化準確性:通過最小化預測誤差,使泛化模型在每個觀測時間點都能準確預測實際數據。
  • 重構一致性:確保模型參數在原始空間與庫普曼空間之間的轉換具有一致性。
  • 動態保真性:約束庫普曼空間的動態行為,使得映射后的空間符合預期的動態系統特征。
  • 參數一致性:確保泛化模型參數映射回原始空間后與預測模型參數保持一致。

利用庫普曼算子評估和控制泛化過程:引入庫普曼理論的另一優勢在于,我們可以通過庫普曼算子的譜特性來評估模型的長期穩定性。此外,還可以在庫普曼算子中施加約束來控制模型的動態行為。

1.?系統穩定性評估

通過觀察庫普曼算子的特征值,可以判斷系統是否穩定:

  • 若所有特征值實部為負,系統會穩定地趨向于一個平衡狀態。
  • 若存在特征值實部為正,系統將變得不穩定,模型在未來可能會崩塌。
  • 若特征值實部為零,系統可能表現出周期性行為。通過分析這些特征值的分布,我們可以預測系統的長期行為,識別模型在未來是否可能出現崩潰的風險。

2.?泛化過程約束

我們可以通過對庫普曼算子施加顯式約束來調控模型的動態行為。例如:

  • 周期性約束:當數據動態為周期性時,可將庫普曼算子設為反對稱矩陣,使其特征值為純虛數,從而使模型表現出周期性行為。
  • 低秩近似:將表示為低秩矩陣,有助于控制模型的自由度,避免過擬合到次要信息。

通過這些手段,我們不僅提高了泛化的長期穩定性,還增強了模型在特定任務中的可控性。?

06?實驗

6.1 實驗設置

為驗證算法效果,我們使用了合成數據集和多種真實世界場景的數據集:

合成數據集:包括 Rotated 2-Moons 和 Rotated MNIST 數據集,通過在連續時間區間內隨機生成時間戳,并對 Moons 和 MNIST 數據按時間戳逐步旋轉生成連續時域。

真實世界數據集

  • 事件驅動數據集?Cyclone:基于熱帶氣旋的衛星圖像預測風力強度,氣旋發生日期對應連續時域。
  • 流數據集?Twitter 和 House:分別從任意時間段抽取推文和房價數據流構成一個領域,多次隨機抽取形成連續時域。
  • 不規則離散數據集?Yearbook:人像圖片預測性別,從 84 年中隨機抽取 40 年數據作為連續時域。

6.2 實驗結果與分析

定量分析

我們首先對比了 Koodos 方法與各基線方法的定量性能。表 1 顯示,Koodos 方法在所有數據集上展現了顯著的性能提升。

在合成數據集上,Koodos 能夠輕松應對持續的概念漂移,而所有基線方法在這種場景下全部失效。

在真實世界數據集上,盡管某些基線方法(如 CIDA、DRAIN 和 DeepODE)在少數場景中略有表現,但其相較于簡單方法(如 Offline)的改進非常有限。相比之下,Koodos 顯著優于所有現有方法,彰顯出在時域泛化任務中考慮分布連續變化的關鍵作用。

圖片

▲ 實驗結果

定性分析

決策邊界:為直觀展示泛化效果,我們在 Rotated 2-Moons 數據集上進行了決策邊界的可視化。該任務具有極高難度:模型需在 0 到 35 秒左右的 35 個連續時域上訓練,隨后泛化到不規律分布在 35 到 50 秒的 15 個測試域。而現有方法通常只能泛化至未來的一個時域(T+1),且難以處理不規律的時間分布。圖 3 從 15 個測試域中選取了 7 個進行可視化。結果清晰地表明,基線方法在應對連續時域的動態變化時表現不足。隨著時間推進,決策邊界逐漸偏離理想狀態。尤其是最新的 DRAIN 方法(ICLR23)在多步泛化任務中明顯失效。

相比之下,Koodos 在所有測試域上展現出卓越的泛化能力,始終保持清晰、準確的決策邊界,與實際數據分布變化高度同步。這一效果突顯了 Koodos 在時域泛化任務中的革命性優勢

圖片

▲ 圖3:2-Moons 數據集決策邊界的可視化(紫色和黃色表示數據區域,紅線表示決策邊界)。從上到下比較了兩種基線方法和 Koodos;從左到右顯示了部分測試域(15 選 7,所有測試域的分布在時間軸上用紅點標記)。

模型演變軌跡:為更深入地分析模型的泛化能力,我們通過 t-SNE 降維,將不同方法的模型參數的演變過程(Model Evolution Trajectory)在隱空間中可視化(圖 4)。

可以看出,Koodos 的軌跡呈現出平滑而有規律的螺旋式上升路徑,從訓練域平滑延伸至測試域。這一軌跡表明,Koodos 能夠在隱空間中有效捕捉數據分布的連續變化,并隨時間自然地擴展泛化。

相比之下,基線模型的軌跡在隱空間中缺乏清晰結構,隨著時間推移,逐漸出現明顯的偏離,未能形成一致的動態模式。

圖片

▲ 圖4:模型狀態在隱空間中的時空軌跡。Koodos 展現出與數據動態和諧同步的模型動態。

時域泛化的分析與控制:在 Koodos 模型中,庫普曼算子為分析模型動態提供了有效手段。我們對 Koodos 在 2-Moons 數據集上分析表明,庫普曼算子的特征值在復平面上分布在穩定區和不穩定區,這意味著 Koodos 在中短期內能穩定泛化,但在極長時間的預測上將會逐漸失去穩定性,偏離預期路徑(圖 5b)。

為提升模型的穩定性,我們通過將庫普曼算子配置為反對稱矩陣(即Koodos版本),確保所有特征值為純虛數,使模型具有周期性穩定特性。在這一配置下,Koodos展現出高度一致的軌跡,即使在長時間外推過程中依然保持穩定和準確,證明了引入先驗知識對增強模型穩健性的效果(圖 5c)。

?,時長00:23

▲ 圖5:非受控和受控條件下的極長期泛化預測模型軌跡。a:部分訓練域數據;b:不受控,模型最終偏離預期;c:受控,模型始終穩定且準確。

▲ 圖5:非受控和受控條件下的極長期泛化預測模型軌跡。a:部分訓練域數據;b:不受控,模型最終偏離預期;c:受控,模型始終穩定且準確。?

07?結論

我們設計了一種基于模型連續動態系統的時域泛化方法,能夠在數據域隨時間逐漸演變的環境中,實現泛化模型的穩定性與可控性。未來,我們計劃從多個方向進一步拓展這一技術的應用:

生成式模型擴展:時域泛化與生成式模型任務有天然的關聯,Koodos 所具備的泛化能力能夠為神經網絡生成技術帶來新的可能。

非時態泛化任務:Koodos 的應用并不局限于時域泛化,它也可以適用于其他分布變化的任務中。我們計劃探索其在非時態領域的應用。

大模型集成:我們將探索時域泛化在大模型中的集成,幫助 LLM 在復雜多變的分布中保持魯棒性和穩定性。

我們對時域泛化任務在未來的廣闊應用前景充滿期待。如有任何問題或合作意向,歡迎聯系我們!

郵箱:?caizekun@csis.u-tokyo.ac.jp

GitHub:???https://github.com/Zekun-Cai/Koodos/??

Paper:???https://arxiv.org/pdf/2405.16075??

#Scaling Laws for Precision 解讀

本文探討了模型量化對性能的影響,并提供了關于訓練時量化和后訓練量化的實用建議。文章強調了在不同訓練精度下,如何平衡模型性能和量化損失,以及在實際應用中選擇合適的量化策略的重要性。

來自鏈接?https://zhuanlan.zhihu.com/p/6848989432

原文

  • ??https://arxiv.org/abs/2411.04330??

前置知識:

scaling law:

  • Training Compute-Optimal Large Language Models(Chinchilla scaling law)

個人討厭晦澀難懂+無法應用于實際場景的"裝逼結論",因此先按照自己的理解幫大家rephrase一下論文的主要發現(in plain language):

首先,這是一篇研究精度(precision)、參數量(parameters)和訓練數據量(tokens)之間關系的重要論文。

1. 關于后訓練量化(Post-Training Quantization, PTQ):1.1 基本概念

  • 指的是pretrain以較高精度(bf16)進行,結束后再量化到更低精度(如int4)

1.2 結論1

模型預訓練的trained_token/parameter比率越高,預訓練結束后,使用PTQ帶來的性能下降就越大。這里作者沒寫明白有誤導性!!!實際上這個結論指的是:

  • 我們都知道PTQ一定會帶來性能下降(PTQ后,valid loss相比pretrain之后會上升),這個下降可以用
  • 論文提出了預測這個下降值的公式:
  • 其中:
  • 訓練數據量D越大,PTQ帶來的損失越大(正相關)
  • 參數量N越大,PTQ帶來的損失越小(負相關)
  • 量化后的精度Ppost越低,損失增加越多(負指數關系)
  • N: 參數量
  • D: 訓練token數
  • : PTQ后的精度
  • γγγ: 擬合常數
  • 這個公式告訴我們:
  • 注意,δPTQ還有一種完整形式(section 5) 同時考慮了訓練精度和推理精度(繼續往后看):
  • 那么如果你必須進行PTQ,那么對于同樣參數量大小的模型,被訓更多token的模型的 δPTQ 會比喂更少數據的模型要大。但最終loss的絕對數量是多少并不一定,因為即便 δPTQ 這個正數會讓loss上升(性能下降),但模型終歸被訓了更多數據,這么一抵消可能loss還是會下降。相當于兩只無形的手(數據量的上升帶來的loss下降、PTQ帶來的loss上升)在掰手腕;給定模型參數量和固定的精度,具體誰能掰過誰會有一個打平手的cutoff數據量。
  • 舉例子,如果你要固定70B模型參數量并pretrain時候采用bf16,并且pretrain后要PTQ到int4。那么采用兩種數據量:
  • a) 用10B token訓出來模型
  • b) 5B token訓出來的模型

  • 那么一定是a)情況的 δPTQ 更大,但最終PTQ結束之后的loss的數值是多少就不一定了。

  • 因此作者也在原文中提到了**there exists an amount of pretraining data beyond which additional data is actively harmful to performance at inference-time (see top-left, Figure 2),也就是給定你要進行PTQ,那么對于你的實驗設置,總有一個cutoff的數據量,稱之為臨界的數據量 Dcrit ,超過這個量后繼續訓練會導致PTQ后性能下降。這個臨界點并不是說超過后訓練數據就“有害”,而是說在進行PTQ后,性能的提升可能會被性能的下降所抵消。因此,在實際應用中,需要權衡訓練數據量與模型量化后的性能。

  • 論文給出了計算這個臨界點的公式:

其他結論

  • 在某些情況下,過度訓練(more tokens)反而會讓PTQ后的模型性能變差
  • 更大的模型在相同的token/parameter比率下,對PTQ更魯棒
  • 對于固定大小的數據集,增加模型參數量可以提高PTQ的魯棒性
  • 這種規律在不同的PTQ方法中都存在(論文驗證了GPTQ、AWQ和RTN三種方法)

訓練精度的影響

  • 訓練時使用較低精度的模型在PTQ時性能下降較小
  • 如果你知道模型最終需要被量化到很低的精度(比如4bit),那么在訓練時就使用相對較低的精度(比如8bit)可能比使用高精度(比如16bit)更好,因為這樣可以讓模型在訓練過程中就適應量化噪聲。
  • 實話說這個結論初看有點脫褲子放屁,因為太符合直覺了(bushi)。用腳想想就知道【訓練用int8然后量化到int4】肯定比【訓練用bf16然后量化到int4】要好,原文section 5:models trained in lower precision are more robust to post-train quantization in the sense of incurring lower degradation.
  • 這也解釋了為什么一些較新的大語言模型傾向于使用BF16而不是FP32來訓練,因為這不僅可以節省計算資源,還可能讓模型在后續量化時表現更好

1.3 PTQ造成loss degradation的深入分析1.3.1 兩個競爭效應(section 5)

在分析PTQ對模型性能的影響時,論文發現了兩個相互競爭的效應:

  1. Robustification效應
  2. 低精度訓練會讓模型更適應量化噪聲
  3. 這使得模型在后續PTQ時更加魯棒
  4. 可以理解為模型學會了如何在噪聲環境中運作
  5. Overtraining效應
  6. 低精度訓練會降低模型的有效參數量(),這意味著模型在相同的數據量下“看起來”參數量更少,從而在PTQ時對參數量化的敏感性增加
  7. 因為??和??成正比, 較低的Neff理論上會導致更大的性能下降: (section 5這邊第一次讀還以為寫錯了)。作者說的??實際上應該參考公式 9 變為??,隨著??的增加,??確實增加, 也就是成正比。說明白點就是低精度訓練會下降Neff, 也就是一個??模型的可能有效的參數只有 10 B , 然后??變大, 然后根據section 3 的公式就會造成更大的degradation)
  8. 這個效應與Robustification效應相反

在實踐中,Robustification效應通常占主導,這就是為什么低精度訓練的模型在PTQ時表現更好。

1.3.2 精度閾值效應

一個重要發現是,當精度低于5-bit時,PTQ帶來的性能下降會急劇增加:

  • 在高精度區間(如8-bit以上),D/N比率的增加對性能的影響相對溫和
  • 在5-bit以下,即使很小的D/N比率增加也可能導致顯著的性能下降
  • 這個發現對實踐中選擇量化精度有重要指導意義--?在實際應用中,應避免將模型量化到低于5-bit的精度,除非有特定的需求和相應的優化技術支持

1.3.3 理論解釋

論文在附錄中提供了兩個可能的理論解釋:

Sharpness假說

  • 模型在訓練過程中會逐漸變得更"sharp"-- 隨著訓練的進行,模型的損失函數變得更加“尖銳”(sharp),即梯度和Hessian矩陣的特征值增加,這導致模型對參數擾動更加敏感。因此,PTQ帶來的參數量化噪聲會對尖銳的損失函數產生更大的影響。
  • Sharp的模型對參數擾動更敏感
  • 這種敏感性會隨著訓練的進行而增加
  • 這解釋了為什么過度訓練可能導致更大的PTQ降質

分層學習假說

  • 模型通過分層方式學習特征-- 模型通過逐步學習更復雜的特征,這些特征依賴于之前學習的基礎特征。量化噪聲影響基礎特征,會級聯地影響到更高層次的復雜特征,從而導致整體性能的下降。
  • 早期學習基礎特征,后期學習復雜特征
  • 復雜特征依賴于基礎特征的準確性
  • 當基礎特征受到量化噪聲影響時,會對依賴它們的復雜特征造成級聯效應
  • 這解釋了為什么訓練時間越長,模型對量化越敏感

2. 關于訓練時量化(Training-time Quantization)

2.1 基本概念

論文中將訓練時量化分為兩種情況:

  • 僅量化權重(Quantization-Aware Training, QAT):只將模型的權重量化到低精度,其他部分保持高精度,以適應推理階段的低精度環境。
  • 全面量化(Low-precision Training):同時量化模型的權重、激活值和注意力計算(即鍵-值緩存),以減少計算資源需求。

注意:這里的權重指模型中所有線性層(Linear layers)的權重矩陣,包括:

  • Transformer 中的所有投影矩陣(例如 query、key、value 的投影權重);
  • 嵌入層(Embedding layers)權重矩陣;
  • 最終輸出層的權重矩陣。

但在論文的實驗中未對嵌入層(Embedding layer)進行量化。

量化實現細節:

  • 論文遵循了 FP8 訓練的標準規范(Micikevicius et al., 2022);
  • 權重采用?按通道(per-channel)?量化;
  • 激活值采用?按張量(per-tensor)?量化;
  • 對于后訓練量化(PTQ),主要針對模型權重進行量化。

2.2 核心發現

權重、激活值和注意力的量化效果是獨立且可乘的,這一點非常關鍵。

論文提出了“有效參數量?Neff?effective parameter count)”的概念。簡而言之, Neff?代表了模型在低精度下的“真實有效”參數量。在低精度訓練時,模型的實際參數量 N會被折減為較低的 Neff ,這有助于評估模型在低精度量化下的性能損失。

基本形式:

完整形式(全面量化):

其中:

  • N:模型的實際參數量;
  • Pw :權重精度;
  • Pa:激活值精度;
  • Pkv :注意力計算精度;
  • γw、γa、γkv :各部分的敏感度系數,反映了模型對不同量化精度的適應性。

舉個例子,在相同的計算預算下,有兩種方案:

  • a) 使用 16-bit 精度訓練較小的模型;
  • b) 使用 8-bit 精度訓練較大的模型(參數量約為前者的 2 倍)。

根據論文的?Neff?分析,第二種方案通常更優,因為:

  1. 增加的參數量帶來的性能提升超過了精度降低造成的損失;
  2. 8-bit 精度已接近論文中發現的計算最優精度(7-8 bits);
  3. 低精度訓練可以在相同的計算預算下處理更多的數據。

最優訓練精度的計算:論文發現,在一般情況下,最優的訓練精度為?7-8 bits這意味著當前常用的 16-bit(BF16)訓練精度其實存在冗余。但如果追求極低精度(例如 4-bit 以下),則需要不成比例地增加模型大小才能維持性能。

但是,如果模型大小被固定(例如受限于硬件資源),情況會有所不同:

  • 此時,最優訓練精度會隨著訓練數據量的增加而提高。具體來說,最優精度與訓練數據量和參數量的比值成對數關系,即:

最優精度訓練數據量參數量最優精度∝log?(訓練數據量參數量)(見論文 Section 4.3.3)

2.3 訓練成本分析

訓練成本的計算公式如下:

其中:

  • C:計算成本;
  • N :模型參數量;
  • D :訓練 token 數;
  • P :訓練精度;
  • 6/16:標準化系數(基于 Chinchilla 成本模型)。

這意味著什么??舉個例子:假設你的計算預算是固定的,希望訓練一個模型,有兩種選擇:

  • 使用 16-bit 精度訓練一個 35B 參數量的模型;
  • 使用 8-bit 精度訓練一個 70B 參數量的模型。

根據論文的發現,第二種方案可能更優,因為增加的參數量帶來的性能提升超過了精度降低帶來的損失。

2.4 實踐建議

如果計算預算有限:

  • 優先選擇?7-8 bit?的訓練精度,并利用節省下來的資源增加模型參數量;
  • 避免使用低于 4-bit 的訓練精度,因為這需要大幅增加模型大小才能維持性能(見論文 Section 4.3.2)。

如果模型大小受限:

  • 在需要處理更大量數據時,提高訓練精度;
  • 例如,當 token/parameter 比率超過 1000 時,建議使用 8-bit 以上的精度;
  • 在高 token/parameter 比率下,避免使用低于 6-bit 的訓練精度(見論文 Section 4.3.3)。

各部分的精度選擇:

  • 權重(Weights)在極低精度(3-bit)下仍能保持穩定;
  • 激活值(Activations)注意力計算(KV-cache)在低于 3-bit 時可能會出現不穩定;
  • 這種差異可能與量化方式有關(權重采用按通道量化,激活值采用按張量量化),而不一定是固有特性。

3.限制與未來研究方向

3.1 固定的模型架構

這篇論文采用了固定的Transformer++架構,以便在一個可控的環境中分析精度、參數量和數據量之間的關系。然而,在實際應用中,低精度訓練通常會伴隨著模型架構的調整。例如,一些先進的低精度訓練方法可能會引入特殊的正則化技術或優化策略,以減輕低精度帶來的負面影響。因此,論文的結論主要適用于固定架構的情況,尚未在經過優化的低精度架構中進行驗證

3.2 計算成本與系統開銷

雖然理論上,降低訓練精度(比如從16-bit降到8-bit)可以按比例減少計算需求,但在實際操作中,由于系統開銷和硬件實現的限制,精度降低所帶來的性能提升通常低于理論預期。例如,某些硬件可能無法高效支持極低精度(如4-bit以下)的計算,導致實際的加速效果有限。此外,不同精度下的數據移動和存儲優化表現也可能有所不同,這進一步影響了低精度訓練的實際效率。

3.3 僅關注驗證損失,缺乏下游任務評估

論文主要關注于訓練過程中的驗證損失(validation loss)作為性能評估指標,而沒有對下游任務的具體表現進行評估。盡管驗證損失是衡量模型性能的重要指標,但不同任務對模型精度和量化的敏感性可能存在差異

3.4 實驗規模的限制

雖然論文中訓練了多達17億(17B)參數的模型,并使用了高達26B tokens的數據集,但這些規模相對較小,與當前最先進的大規模語言模型(如數百億甚至千億參數級別)相比仍有差距。因此,論文的scaling law在更大規模模型上的適用性尚未得到驗證

4. 量化方法的多樣性

這篇論文主要關注于整數類型的量化方法,并通過GPTQ、AWQ和RTN等方法進行了驗證。然而,浮點類型的量化方法(如FP8、FP4)在實際應用中也具有重要意義,尤其是在某些硬件平臺上具有更好的支持和性能表現。不同量化方法在引入量化噪聲和影響模型性能方面可能存在顯著差異,因此,未來的研究應涵蓋更多種類的量化方法,以全面理解量化對模型性能的影響

5. 數據集和訓練策略的單一性

這篇論文使用了Dolma V1.7數據集,并采用了特定的訓練策略和超參數設置。不同的數據集和訓練策略可能會影響模型對量化的敏感性。例如,某些數據集可能具有更高的復雜性或多樣性,導致模型在低精度下表現出不同的魯棒性。因此,未來的研究應在多樣化的數據集和訓練配置下進行,以驗證縮放規律的普適性

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63039.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63039.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63039.shtml

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

相關文章

Flutter Navigator2.0的原理和Web端實踐

01 背景與動機 在Navigator 2.0推出之前&#xff0c;Flutter主要通過Navigator 1.0和其提供的 API&#xff08;如push(), pop(), pushNamed()等&#xff09;來管理頁面路由。然而&#xff0c;Navigator 1.0存在一些局限性&#xff0c;如難以實現復雜的頁面操作&#xff08;如移…

代碼隨想錄算法訓練營第三天 | 鏈表理論基礎 | 707.設計鏈表

要求太多&#xff0c;代碼量太大&#xff0c;實在難以完成 在以前聽說&#xff0c;好的程序員&#xff0c;可以在短時生成大量的代碼&#xff0c;本題只方法才只有6個&#xff0c;根本不算多 每天手敲代碼量太少&#xff0c;才是問題 #include <iostream>class MyLink…

數據冒險、控制冒險、結構冒險

計算機組成原理 數據冒險、控制冒險、結構冒險 對所有用戶&#xff08;所有程序員&#xff09;可見&#xff1a;PSW、PC、通用寄存器 PSW&#xff08;條件轉移需要用到&#xff0c;程序員使用CMP指令的時候也需要用到所以是對用戶可見&#xff09;PC&#xff08;跳轉指令需要…

基于32單片機的RS485綜合土壤傳感器檢測土壤PH、氮磷鉀的使用(超詳細)

1-3為RS485綜合土壤傳感器的基本內容 4-5為基于STM32F103C8T6單片機使用RS485傳感器檢測土壤PH、氮磷鉀并顯示在OLED顯示屏的相關配置內容 注意&#xff1a;本篇文件講解使用的是PH、氮磷鉀四合一RS485綜合土壤傳感器&#xff0c;但里面的講解內容適配市面上的所有多合一的RS…

SpringBoot【十一】mybatis-plus實現多數據源配置,開箱即用!

一、前言&#x1f525; 環境說明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 正常情況下我們在開發系統的時候都是使用一個數據源&#xff0c;但是由于有些項目同步數據的時候不想造成數據庫io消耗壓力過大&#xff0c;便會一個項目對應多個數據源…

Node.js教程入門第一課:環境安裝

對于一個程序員來說&#xff0c;每學習一個新東西的時候&#xff0c;第一步基本上都是先進行環境的搭建&#xff01; 從本章節開始讓我們開始探索Node.js的世界吧! 什么是Node.js? 那么什么是Node.js呢&#xff1f;簡單的說Node.js 就是運行在服務端的 JavaScript JavaScript…

vim優化

1.編輯如下內容&#xff1a; cat > /root/.vimrc <<EOF set tabstop2 " 設置 Tab 為 2 個空格 set shiftwidth2 " 設置自動縮進為 2 個空格 set expandtab " 將 Tab 轉換為空格 " 基本設置 set number syntax on" 快捷鍵設置…

字符串性能對比

效率(1) : String.indexOf與String.contains效率測試_string contains效率-CSDN博客 結論是前者效率高&#xff0c;源碼里面conatins是使用indexof 在jdk8中contains直接調用的indexOf(其他版本沒有驗證),所以要說效率來說肯定是indexOf高,但contains也就多了一層方法棧,so 什…

移動網絡的原理

無線網絡是如何解決移動通信問題的 場景&#xff1a;用戶在一輛轎車內以150km/h的時速沿高速公路急速行駛時穿過多個無線接入網&#xff0c;用戶希望在整個旅程中保持一個與遠程應用的不間斷的TCP連接。 解決方案&#xff1a;移動節點的間接路由選擇方法可解決TCP鏈接不間斷的…

python學opencv|讀取圖像(十三)BGR圖像和HSV圖像互相轉換深入

【1】引言 前序學習過程中&#xff0c;我們偶然發現&#xff1a;如果原始圖像是png格式&#xff0c;將其從BGR轉向HSV&#xff0c;再從HSV轉回BGR后&#xff0c;圖像的效果要好于JPG格式。 文章鏈接為&#xff1a; python學opencv|讀取圖像&#xff08;十二&#xff09;BGR圖…

解決node.js的req.body為空的問題

從昨晚一直在試&#xff0c;明明之前用的封裝的axios發送請求給其他的后端&#xff08;springboot&#xff09;是可以的&#xff0c;但昨天用了新項目的后端&#xff08;node.js&#xff09;就不行。 之前用了代理&#xff0c;所以瀏覽器發送的post請求不會被攔截&#xff0c;…

【嵌入式】嵌入式面試題 36 問

1. volatile 是否可以修飾 const 是的&#xff0c;volatile 可以修飾 const。const 表示變量的值不能被修改&#xff0c;而 volatile 表示變量的值可能在程序之外被修改&#xff08;例如&#xff0c;由硬件修改&#xff09;。 將 volatile 用于 const 變量意味著該變量的值雖然…

java基礎概念49-數據結構2

一、樹 1-1、樹的基本概念 1、樹的節點 2、二叉樹 3、樹的高度 1-2、二叉查找樹 普通二叉樹沒有規律&#xff0c;不方便查找&#xff0c;沒什么作用。 1、基本概念 2、添加節點 此時&#xff0c;該方式添加形成的二叉查找樹&#xff0c;根節點就是第一個節點。 3、查找節點 4…

GhatGPT缺陷不足和商業應用

1. 引言 ChatGPT的興起&#xff1a; 2022年末推出&#xff0c;迅速在自然語言處理和人工智能領域引起廣泛關注。數億用戶體驗其強大智能&#xff0c;感嘆機器智能的飛速發展。 存在的缺陷&#xff1a; 事實性錯誤&#xff1a;生成的文本中包含錯誤信息。無法實時更新&#xff1…

【Linux】Macvlan介紹及LInux下例子實現

Macvlan Macvlan 是一種網絡虛擬化技術&#xff0c;允許在同一物理網絡接口上創建多個虛擬網絡接口&#xff0c;每個虛擬接口都有自己獨立的 MAC 地址。這對于需要在同一物理主機上運行多個網絡隔離的應用程序或容器時非常有用。 Macvlan 的特點和用途 獨立的 MAC 地址 每個 …

Jackson @JsonInclude 注解

1. 概述 Jackson 是一個著名的Java庫&#xff0c;以轉換Java對象為JSON格式以及從JSON反序列化回Java對象而聞名。有時候&#xff0c;我們可能希望僅在某些字段滿足特定條件時才將其包含在JSON輸出中&#xff0c;而Jackson的JsonInclude注解正是為此目的量身定制的。 JsonInc…

12.12 枚舉 共用體 數據結構 創建順序表

1.思維導圖 2. 創建順序表 1>頭文件 test.h #ifndef __TEST_H__ #define __TEST_H__#include<stdlib.h> #include<stdio.h> #include<string.h>#define MAX 30 //typedef int datatype;typedef struct sequence {int data[MAX];int len;}seqlist,*se…

next.js 存在緩存中毒漏洞(CVE-2024-46982)

免責聲明: 本文旨在提供有關特定漏洞的深入信息,幫助用戶充分了解潛在的安全風險。發布此信息的目的在于提升網絡安全意識和推動技術進步,未經授權訪問系統、網絡或應用程序,可能會導致法律責任或嚴重后果。因此,作者不對讀者基于本文內容所采取的任何行為承擔責任。讀者在…

如何對小型固定翼無人機進行最優的路徑跟隨控制?

控制架構 文章繼續采用的是 ULTRA-Extra無人機&#xff0c;相關參數如下&#xff1a; 這里用于guidance law的無人機運動學模型為&#xff1a; { x ˙ p V a cos ? γ cos ? χ V w cos ? γ w cos ? χ w y ˙ p V a cos ? γ sin ? χ V w cos ? γ w sin ? χ…

【Flink-scala】DataStream編程模型之延遲數據處理

DataStream API編程模型 1.【Flink-Scala】DataStream編程模型之數據源、數據轉換、數據輸出 2.【Flink-scala】DataStream編程模型之 窗口的劃分-時間概念-窗口計算程序 3.【Flink-scala】DataStream編程模型之水位線 4.【Flink-scala】DataStream編程模型之窗口計算-觸發器-…