我來小小的理解一下:
首先,16 batchsize,60sequendcelength,7 個特征的通俗解釋
16 個獨立的樣本,每個樣本有 60 個連續的時間步及對應的標簽值,每個時間步有 60 個特征
所以就是因為樣本是隨機從訓練集中采的,所以就假設采的是
樣本 1,樣本 6,樣本 109,樣本 334,樣本 354等等等,一共 16 個(這就是 batchsize,表示一個 batch中容納的樣本數)
接下來,每個樣本中連續的 60 個時間步,這個就很好理解了,但是這 60 個連續的時間步:
(0)樣本 1:可能從第 7 個時間開始.....跟著 60 個,后面緊跟著要預測的 24 個時間步,dataloader 讀數據時都封裝好了,會對應上的
(1)樣本 6:從第? 38 個時間開始.....
(2)樣本109:從第 1 個時間開始
......
(15)樣本 334:從第 129 個時間開始
總之就是這樣,然后每個時間有 7 個特征表示
接下來 16x60x7 --》 16×7×60
就是:
(0)樣本 1:特征 1[60個連續的時間步],特征 2,特征 3,,,,,特征 7
(1)樣本 6:特征 1,特征 2,特征 3,,,,,特征 7
(2)樣本109:特征 1,特征 2,特征 3,,,,,特征 7
......
(15)樣本 334:特征 1,特征 2,特征 3,,,,,特征 7
每個特征分別有 60 個連續的時間步
接下來呢,又開始對于這 60 個時間步,分段,分成 5 段,每段 12 個
然后呢,就把分出來的 段,12 維 統統喂到 linear 中,嵌入到 512 維,用的一個嵌入空間,所以嵌入時使用權值矩陣是一樣的,畢竟得在同一個準則下才有可比性,這一步就是學習了每一個小段內,時間之間的相關關系
代碼中搞事情:
它把樣本batch 維度和特征維度,混到一起寫,reshape 成(-1,seg_num_x,seg_dim)
(0)樣本 1-特征 1 :【12】【12】【12】【12】【12】
(0)樣本 1-特征 2?:【12】【12】【12】【12】【12】
....
(0)樣本 1-特征 7?:【12】【12】【12】【12】【12】
(1)樣本 6-特征 1 :【12】【12】【12】【12】【12】
(1)樣本 6-特征 2?:【12】【12】【12】【12】【12】
....
(1)樣本 6-特征 7?:【12】【12】【12】【12】【12】
(15)樣本 334-特征 1 :【12】【12】【12】【12】【12】
(15)樣本 334-特征 2?:【12】【12】【12】【12】【12】
....
(15)樣本 334-特征 7?:【12】【12】【12】【12】【12】
也就是 112 條序列、、、 112×5×12
linear 就是把所有的 12 全部嵌入到 512 維
112×5×512
(0)樣本 1-特征 1 :【512】【512】【512】【512】【512】→ 5步GRU → hn[0,0]
(0)樣本 1-特征 2?:【512】【512】【512】【512】【512】→ 5步GRU → hn[0,1]
....
(0)樣本 1-特征 7?:【512】【512】【512】【512】【512】→ 5步GRU → hn[0,6]
(1)樣本 6-特征 1 :【512】【512】【512】【512】【512】→ 5步GRU → hn[0,7]
(1)樣本 6-特征 2?:【512】【512】【512】【512】【512】→ 5步GRU → hn[0,8]
....
(1)樣本 6-特征 7?:【512】【512】【512】【512】【512】
(15)樣本 334-特征 1 :【512】【512】【512】【512】【512】
(15)樣本 334-特征 2?:【512】【512】【512】【512】【512】
....
(15)樣本 334-特征 7?:【512】【512】【512】【512】【512】→ 5步GRU → hn[0,111]
接下來 段內建模完了,那相鄰段之間的時間的關系還沒有建模呀,就把這些統統喂到 RNN 中,
RNN 把這個當做 5 個時間步,112 當成新的 batch,RNN 的 hiddensize 也設置成了 512(源碼中寫了),也就是?
單層 GRU(文中實際上用的 RNN 單元)
[序列 1] → 5步GRU → hn[0,0]
[序列 2] → 5步GRU → hn[0,1]
...
[序列 8] → 5步GRU → hn[0,7]
...
[序列 112] → 5步GRU → hn[0,111]
實際上這個 hn 應該是三維的,畢竟輸入就是三維的,h_n.shape=1×112×512
應該是:
[序列 1] →?hn[0, 0, :] - 批次0-特征0的最終隱藏狀態
[序列 2] →?hn[0, 1, :] - 批次0-特征1的最終隱藏狀態
...
[序列 8] →?hn[0, 7, :] - 批次1-特征0的最終隱藏狀態
...
[序列 112] →?hn[0, 111, :] - 批次15-特征6的最終隱藏狀態
如果模型使用了多層GRU(例如num_layers=2),則隱藏狀態的第一維將為2,我們會有:
- hn[0,i,:]?- 第一層GRU對序列i的最終隱藏狀態
- hn[1,i,:]?- 第二層GRU對序列i的最終隱藏狀態
但我們的num_layers=1
笑死,看了一天,居然覺得這么做也沒啥不好的,習慣這個有點反常識的表示了。
傳統 RNN 是:
16×60×7,其實就是:
(1)樣本 6:從第? 38 個時間開始.....?→ 60步GRU 建模? 7 維 →hn[0,0]?512 維(融合了所有時間步信息的 512 維)
(2)樣本109:從第 1 個時間開始→ 60步GRU 建模? 7 維→ hn[0,1] 512 維
......
(15)樣本 334:從第 129 個時間開始→ 60步GRU → hn[0,15] 512 維?
解碼的時候還原,其實是一樣的
- 16個樣本確實是隨機采樣的,不一定是連續的樣本
- 每個樣本的60個時間步確實是連續的時間序列片段
- 不同樣本可以從各自時間序列的不同位置開始
- "嵌入時使用權值矩陣是一樣的,畢竟得在同一個準則下才有可比性"
- RNN把5個段作為5個時間步處理
- 每個序列有自己獨立的隱藏狀態流
- 所有序列共享同一個RNN的參數
- 第一個維度0表示GRU層索引(因為只有1層)
- 第二個維度i表示112個序列中的第i個
- 第三個維度表示512維隱藏狀態
- 傳統RNN: 每個批次作為一個整體,60個時間步直接輸入
- SegRNN: 每個批次-特征組合作為獨立序列,5個段作為時間步輸入
明天看解碼過程