優(yōu)秀的設(shè)計(jì)網(wǎng)站有哪些內(nèi)容上海網(wǎng)站優(yōu)化上
鶴壁市浩天電氣有限公司
2026/01/24 14:41:35
優(yōu)秀的設(shè)計(jì)網(wǎng)站有哪些內(nèi)容,上海網(wǎng)站優(yōu)化上,體育論壇網(wǎng)站建設(shè),重慶住房城鄉(xiāng)建設(shè)廳官方網(wǎng)站循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)深度學(xué)習(xí)筆記
目錄
動(dòng)機(jī)#xff1a;為什么需要RNN數(shù)學(xué)基礎(chǔ)優(yōu)化算法工程方法批判性思維技能附錄#xff1a;完整代碼示例 1. 動(dòng)機(jī)#xff1a;為什么需要RNN
1.1 問(wèn)題背景
在現(xiàn)實(shí)世界中#xff0c;我們經(jīng)常遇到序列數(shù)據(jù)#xff1a;
自然語(yǔ)言處理…循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)深度學(xué)習(xí)筆記目錄動(dòng)機(jī)為什么需要RNN數(shù)學(xué)基礎(chǔ)優(yōu)化算法工程方法批判性思維技能附錄完整代碼示例1. 動(dòng)機(jī)為什么需要RNN1.1 問(wèn)題背景在現(xiàn)實(shí)世界中我們經(jīng)常遇到序列數(shù)據(jù)自然語(yǔ)言處理一句話是單詞的序列前面的詞會(huì)影響后面詞的理解時(shí)間序列預(yù)測(cè)股票價(jià)格、天氣變化、傳感器讀數(shù)語(yǔ)音識(shí)別音頻信號(hào)是時(shí)間序列視頻分析視頻是圖像幀的序列音樂生成音符的序列構(gòu)成旋律核心問(wèn)題傳統(tǒng)的前饋神經(jīng)網(wǎng)絡(luò)Feedforward Neural Network有一個(gè)致命缺陷——無(wú)法處理可變長(zhǎng)度的序列且無(wú)法保留歷史信息。1.2 具體場(chǎng)景分析場(chǎng)景1情感分析輸入: 這部電影的前半部分很無(wú)聊但結(jié)局出人意料地精彩 期望輸出: 正面評(píng)價(jià)如果使用傳統(tǒng)神經(jīng)網(wǎng)絡(luò)需要固定輸入長(zhǎng)度無(wú)聊和精彩會(huì)被獨(dú)立處理無(wú)法理解但的轉(zhuǎn)折關(guān)系無(wú)法捕捉詞序信息場(chǎng)景2機(jī)器翻譯輸入: I love deep learning 期望輸出: 我愛深度學(xué)習(xí)挑戰(zhàn)不同語(yǔ)言的詞序可能不同需要理解整個(gè)句子的語(yǔ)境輸入和輸出長(zhǎng)度可能不同1.3 RNN的核心思想RNN通過(guò)引入記憶機(jī)制解決上述問(wèn)題當(dāng)前時(shí)刻的輸出 f(當(dāng)前輸入, 過(guò)去的記憶)關(guān)鍵特性參數(shù)共享處理每個(gè)時(shí)間步使用相同的參數(shù)循環(huán)連接隱藏狀態(tài)從一個(gè)時(shí)間步傳遞到下一個(gè)時(shí)間步可變長(zhǎng)度可以處理任意長(zhǎng)度的序列類比RNN就像一個(gè)人在閱讀句子每讀一個(gè)詞都會(huì)根據(jù)之前讀到的內(nèi)容記憶來(lái)理解當(dāng)前這個(gè)詞。2. 數(shù)學(xué)基礎(chǔ)2.1 RNN的基本結(jié)構(gòu)2.1.1 核心公式對(duì)于時(shí)間步t ttRNN的計(jì)算過(guò)程如下h t tanh ? ( W h h h t ? 1 W x h x t b h ) y t W h y h t b y egin{aligned} h_t anh(W_{hh} h_{t-1} W_{xh} x_t b_h) \ y_t W_{hy} h_t b_y end{aligned}ht?yt??tanh(Whh?ht?1?Wxh?xt?bh?)Why?ht?by??其中x t ∈ R d x_t in mathbb{R}^0ghprlcqxt?∈Rd時(shí)間步t tt的輸入向量維度為d ddh t ∈ R h h_t in mathbb{R}^{h}ht?∈Rh時(shí)間步t tt的隱藏狀態(tài)維度為h hhh t ? 1 ∈ R h h_{t-1} in mathbb{R}^{h}ht?1?∈Rh上一時(shí)間步的隱藏狀態(tài)y t ∈ R o y_t in mathbb{R}^{o}yt?∈Ro時(shí)間步t tt的輸出維度為o ooW x h ∈ R h × d W_{xh} in mathbb{R}^{h imes d}Wxh?∈Rh×d輸入到隱藏層的權(quán)重矩陣W h h ∈ R h × h W_{hh} in mathbb{R}^{h imes h}Whh?∈Rh×h隱藏層到隱藏層的權(quán)重矩陣循環(huán)權(quán)重W h y ∈ R o × h W_{hy} in mathbb{R}^{o imes h}Why?∈Ro×h隱藏層到輸出的權(quán)重矩陣b h ∈ R h b_h in mathbb{R}^{h}bh?∈Rh隱藏層偏置b y ∈ R o b_y in mathbb{R}^{o}by?∈Ro輸出層偏置2.1.2 展開的計(jì)算圖讓我們看一個(gè)具體例子假設(shè)輸入序列長(zhǎng)度為3時(shí)間步: t0 t1 t2 輸入: x_0 → x_1 → x_2 ↓ ↓ ↓ 隱藏層: h_0 → h_1 → h_2 ↓ ↓ ↓ 輸出: y_0 y_1 y_2數(shù)學(xué)展開h_0 tanh(W_hh * h_{-1} W_xh * x_0 b_h) # h_{-1} 通常初始化為0 h_1 tanh(W_hh * h_0 W_xh * x_1 b_h) h_2 tanh(W_hh * h_1 W_xh * x_2 b_h) y_0 W_hy * h_0 b_y y_1 W_hy * h_1 b_y y_2 W_hy * h_2 b_y2.2 詳細(xì)的維度變化分析這是理解RNN的關(guān)鍵讓我們用一個(gè)具體例子追蹤每一步的維度變化。2.2.1 問(wèn)題設(shè)定假設(shè)我們有以下配置輸入維度d 10 d 10d10例如詞嵌入維度隱藏層維度h 20 h 20h20輸出維度o 5 o 5o5例如5個(gè)類別的分類序列長(zhǎng)度T 3 T 3T3批次大小B 2 B 2B2同時(shí)處理2個(gè)序列2.2.2 單個(gè)時(shí)間步的維度變化輸入數(shù)據(jù)形狀x_t: (B, d) (2, 10)表示2個(gè)樣本每個(gè)樣本是10維向量權(quán)重矩陣形狀W_xh: (h, d) (20, 10) # 輸入到隱藏層 W_hh: (h, h) (20, 20) # 隱藏層到隱藏層循環(huán) W_hy: (o, h) (5, 20) # 隱藏層到輸出 b_h: (h,) (20,) # 隱藏層偏置 b_y: (o,) (5,) # 輸出層偏置前一時(shí)刻隱藏狀態(tài)形狀h_{t-1}: (B, h) (2, 20)計(jì)算過(guò)程與維度變化# 步驟1: W_xh x_t^T# (20, 10) (10, 2) (20, 2)# 轉(zhuǎn)置后: (2, 20)term1x_t W_xh.T# (2, 10) (10, 20) (2, 20)# 步驟2: W_hh h_{t-1}^T# (20, 20) (20, 2) (20, 2)# 轉(zhuǎn)置后: (2, 20)term2h_{t-1} W_hh.T# (2, 20) (20, 20) (2, 20)# 步驟3: 相加并加偏置# (2, 20) (2, 20) (20,) (2, 20)# 廣播機(jī)制: (20,) 自動(dòng)擴(kuò)展為 (2, 20)h_ttanh(term1term2b_h)# (2, 20)# 步驟4: 計(jì)算輸出# (2, 20) (20, 5) (2, 5)y_th_t W_hy.Tb_y# (2, 5)總結(jié)單個(gè)時(shí)間步輸入: x_t (2, 10) h_{t-1} (2, 20) ↓ 輸出: h_t (2, 20) y_t (2, 5)2.2.3 完整序列的維度變化對(duì)于整個(gè)序列T3個(gè)時(shí)間步# 輸入序列X:(B,T,d)(2,3,10)# 可以理解為: 2個(gè)樣本每個(gè)樣本有3個(gè)時(shí)間步每個(gè)時(shí)間步是10維向量# 初始化隱藏狀態(tài)h_0:(B,h)(2,20)# 通常初始化為全0# 時(shí)間步 t0x_0X[:,0,:]# (2, 10) - 取所有樣本的第0個(gè)時(shí)間步h_0tanh(x_0 W_xh.Th_{-1} W_hh.Tb_h)# (2, 20)y_0h_0 W_hy.Tb_y# (2, 5)# 時(shí)間步 t1x_1X[:,1,:]# (2, 10) - 取所有樣本的第1個(gè)時(shí)間步h_1tanh(x_1 W_xh.Th_0 W_hh.Tb_h)# (2, 20)y_1h_1 W_hy.Tb_y# (2, 5)# 時(shí)間步 t2x_2X[:,2,:]# (2, 10) - 取所有樣本的第2個(gè)時(shí)間步h_2tanh(x_2 W_xh.Th_1 W_hh.Tb_h)# (2, 20)y_2h_2 W_hy.Tb_y# (2, 5)# 收集所有輸出Ystack([y_0,y_1,y_2],dim1)# (2, 3, 5)# 形狀: (批次大小, 序列長(zhǎng)度, 輸出維度)可視化維度流動(dòng)時(shí)間維度展開: t0: X[:, 0, :] (2, 10) ──→ h_0 (2, 20) ──→ y_0 (2, 5) ↓ t1: X[:, 1, :] (2, 10) ──→ h_1 (2, 20) ──→ y_1 (2, 5) ↓ t2: X[:, 2, :] (2, 10) ──→ h_2 (2, 20) ──→ y_2 (2, 5) 最終輸出: Y (2, 3, 5)2.2.4 實(shí)際數(shù)據(jù)流示例讓我們用一個(gè)文本分類的具體例子任務(wù)情感分類正面/負(fù)面輸入句子樣本1: I love this movie → [I, love, this, movie] 樣本2: Great film → [Great, film, PAD, PAD]數(shù)據(jù)準(zhǔn)備# 詞匯表vocab{I:0,love:1,this:2,movie:3,Great:4,film:5,PAD:6}# 轉(zhuǎn)換為索引sequence1[0,1,2,3]# I love this moviesequence2[4,5,6,6]# Great film PAD PAD (填充到相同長(zhǎng)度)# 詞嵌入層會(huì)將索引轉(zhuǎn)換為向量# 假設(shè)embedding_dim 10# sequence1 → (4, 10) 的矩陣# sequence2 → (4, 10) 的矩陣# 批次處理Xstack([sequence1_embedded,sequence2_embedded])# X: (2, 4, 10) # 2個(gè)樣本4個(gè)時(shí)間步10維嵌入RNN處理流程# 配置B2(批次大小)T4(序列長(zhǎng)度)d10(嵌入維度)h20(隱藏層維度)o2(輸出維度:正面/負(fù)面)# 初始隱藏狀態(tài)h_initzeros(2,20)# (B, h)# 逐時(shí)間步處理fortinrange(4):x_tX[:,t,:]# (2, 10) - 當(dāng)前時(shí)間步的輸入h_trnn_cell(x_t,h_prev)# (2, 20) - 更新隱藏狀態(tài)h_prevh_t# 最后一個(gè)隱藏狀態(tài)用于分類# h_4: (2, 20)logitsh_4 W_hy.Tb_y# (2, 2)probabilitiessoftmax(logits)# (2, 2)# [[0.8, 0.2], # 樣本1: 80%正面, 20%負(fù)面# [0.9, 0.1]] # 樣本2: 90%正面, 10%負(fù)面2.3 損失函數(shù)2.3.1 序列到序列任務(wù)Sequence-to-Sequence對(duì)于每個(gè)時(shí)間步都有輸出的任務(wù)如語(yǔ)言模型L 1 T ∑ t 1 T L t ( y t , y ^ t ) mathcal{L} frac{1}{T} sum_{t1}^{T} mathcal{L}_t(y_t, hat{y}_t)LT1?t1∑T?Lt?(yt?,y^?t?)交叉熵?fù)p失用于分類L t ? ∑ c 1 C y t ( c ) log ? ( y ^ t ( c ) ) mathcal{L}_t -sum_{c1}^{C} y_t^{(c)} log(hat{y}_t^{(c)})Lt??c1∑C?yt(c)?log(y^?t(c)?)其中C CC是類別數(shù)y t ( c ) y_t^{(c)}yt(c)?是真實(shí)標(biāo)簽的one-hot編碼。2.3.2 序列到單一輸出任務(wù)Sequence-to-One對(duì)于只需要最后輸出的任務(wù)如情感分類L L ( y T , y ^ T ) mathcal{L} mathcal{L}(y_T, hat{y}_T)LL(yT?,y^?T?)只計(jì)算最后一個(gè)時(shí)間步的損失。2.3.3 具體例子語(yǔ)言模型任務(wù)給定前面的詞預(yù)測(cè)下一個(gè)詞輸入序列: I love deep 目標(biāo)序列: love deep learning 時(shí)間步 t0: 輸入 I → 預(yù)測(cè) love 時(shí)間步 t1: 輸入 love → 預(yù)測(cè) deep 時(shí)間步 t2: 輸入 deep → 預(yù)測(cè) learning損失計(jì)算# 假設(shè)詞匯表大小 V 10000# 每個(gè)時(shí)間步的輸出是 (B, V) 的概率分布# y_0 是 love 的one-hot編碼# y_1 是 deep 的one-hot編碼# y_2 是 learning 的one-hot編碼# 總損失loss(CrossEntropy(pred_0,y_0)CrossEntropy(pred_1,y_1)CrossEntropy(pred_2,y_2))/32.4 通過(guò)時(shí)間反向傳播BPTT2.4.1 基本思想由于RNN在時(shí)間上展開反向傳播需要沿著時(shí)間鏈傳遞梯度。前向傳播已知h_0 → h_1 → h_2 → ... → h_T → Loss反向傳播Loss → ?L/?h_T → ?L/?h_{T-1} → ... → ?L/?h_1 → ?L/?h_02.4.2 梯度推導(dǎo)對(duì)于時(shí)間步t tt計(jì)算損失對(duì)隱藏狀態(tài)的梯度? L ? h t ? L ? y t ? y t ? h t ? L ? h t 1 ? h t 1 ? h t frac{partial mathcal{L}}{partial h_t} frac{partial mathcal{L}}{partial y_t} frac{partial y_t}{partial h_t} frac{partial mathcal{L}}{partial h_{t1}} frac{partial h_{t1}}{partial h_t}?ht??L??yt??L??ht??yt???ht1??L??ht??ht1??第一項(xiàng)當(dāng)前時(shí)間步的直接貢獻(xiàn)第二項(xiàng)未來(lái)時(shí)間步的間接貢獻(xiàn)通過(guò)鏈?zhǔn)椒▌t權(quán)重梯度累積? L ? W h h ∑ t 1 T ? L ? h t ? h t ? W h h frac{partial mathcal{L}}{partial W_{hh}} sum_{t1}^{T} frac{partial mathcal{L}}{partial h_t} frac{partial h_t}{partial W_{hh}}?Whh??L?t1∑T??ht??L??Whh??ht??注意由于參數(shù)共享每個(gè)時(shí)間步都對(duì)權(quán)重梯度有貢獻(xiàn)。2.4.3 梯度消失和梯度爆炸問(wèn)題的數(shù)學(xué)根源考慮梯度從時(shí)間步T TT傳播到時(shí)間步t tt? h T ? h t ∏ k t 1 T ? h k ? h k ? 1 ∏ k t 1 T W h h T ? diag ( tanh ? ′ ( a k ? 1 ) ) frac{partial h_T}{partial h_t} prod_{kt1}^{T} frac{partial h_k}{partial h_{k-1}} prod_{kt1}^{T} W_{hh}^T cdot ext{diag}( anh(a_{k-1}))?ht??hT??kt1∏T??hk?1??hk??kt1∏T?WhhT??diag(tanh′(ak?1?))其中a k ? 1 W h h h k ? 2 W x h x k ? 1 b h a_{k-1} W_{hh} h_{k-2} W_{xh} x_{k-1} b_hak?1?Whh?hk?2?Wxh?xk?1?bh?梯度消失如果∣ W h h ∣ 1 |W_{hh}| 1∣Whh?∣1且∣ tanh ? ′ ∣ 1 | anh| 1∣tanh′∣1連乘會(huì)導(dǎo)致梯度指數(shù)衰減結(jié)果長(zhǎng)距離依賴無(wú)法學(xué)習(xí)梯度爆炸如果∣ W h h ∣ 1 |W_{hh}| 1∣Whh?∣1連乘會(huì)導(dǎo)致梯度指數(shù)增長(zhǎng)結(jié)果訓(xùn)練不穩(wěn)定權(quán)重更新過(guò)大直觀理解假設(shè)每一步梯度都乘以 0.5小于1 1步后: 梯度 0.5 2步后: 梯度 0.25 10步后: 梯度 ≈ 0.001 50步后: 梯度 ≈ 0幾乎消失3. 優(yōu)化算法3.1 梯度下降及其變體3.1.1 標(biāo)準(zhǔn)梯度下降SGD更新規(guī)則θ t 1 θ t ? η ? θ L ( θ t ) heta_{t1} heta_t - eta
abla_ heta mathcal{L}( heta_t)θt1?θt??η?θ?L(θt?)其中η etaη是學(xué)習(xí)率。應(yīng)用于RNN# 偽代碼forepochinrange(num_epochs):forbatchindataloader:# 前向傳播outputsrnn(batch.inputs)losscriterion(outputs,batch.targets)# 反向傳播BPTTloss.backward()# 參數(shù)更新forparaminrnn.parameters():param.data-learning_rate*param.grad# 清零梯度rnn.zero_grad()3.1.2 梯度裁剪Gradient Clipping目的防止梯度爆炸方法1按值裁剪g clipped max ? ( min ? ( g , clip_value ) , ? clip_value ) g_{ ext{clipped}} max(min(g, ext{clip\_value}), - ext{clip\_value})gclipped?max(min(g,clip_value),?clip_value)方法2按范數(shù)裁剪更常用g clipped { clip_norm ∥ g ∥ g if ∥ g ∥ clip_norm g otherwise g_{ ext{clipped}} egin{cases} frac{ ext{clip\_norm}}{|g|} g ext{if } |g| ext{clip\_norm} \ g ext{otherwise} end{cases}gclipped?{∥g∥clip_norm?gg?if∥g∥clip_normotherwise?PyTorch實(shí)現(xiàn)importtorch.nn.utilsasnn_utils# 前向和反向傳播loss.backward()# 梯度裁剪nn_utils.clip_grad_norm_(rnn.parameters(),max_norm5.0)# 參數(shù)更新optimizer.step()為什么有效原始梯度: [100, -200, 50] → 范數(shù) ≈ 229 裁剪到 max_norm5: 新梯度: [2.18, -4.36, 1.09] → 范數(shù) 5 保持了梯度方向但限制了幅度3.1.3 Adam優(yōu)化器核心思想動(dòng)量Momentum利用歷史梯度信息自適應(yīng)學(xué)習(xí)率每個(gè)參數(shù)有獨(dú)立的學(xué)習(xí)率數(shù)學(xué)公式m t β 1 m t ? 1 ( 1 ? β 1 ) g t v t β 2 v t ? 1 ( 1 ? β 2 ) g t 2 m ^ t m t 1 ? β 1 t v ^ t v t 1 ? β 2 t θ t 1 θ t ? η v ^ t ? m ^ t egin{aligned} m_t eta_1 m_{t-1} (1 - eta_1) g_t \ v_t eta_2 v_{t-1} (1 - eta_2) g_t^2 \ hat{m}_t frac{m_t}{1 - eta_1^t} \ hat{v}_t frac{v_t}{1 - eta_2^t} \ heta_{t1} heta_t - frac{eta}{sqrt{hat{v}_t} epsilon} hat{m}_t end{aligned}mt?vt?m^t?v^t?θt1??β1?mt?1?(1?β1?)gt?β2?vt?1?(1?β2?)gt2?1?β1t?mt??1?β2t?vt??θt??v^t???η?m^t??其中m t m_tmt?一階矩估計(jì)梯度的移動(dòng)平均v t v_tvt?二階矩估計(jì)梯度平方的移動(dòng)平均β 1 0.9 eta_1 0.9β1?0.9β 2 0.999 eta_2 0.999β2?0.999默認(rèn)值? 1 0 ? 8 epsilon 10^{-8}?10?8數(shù)值穩(wěn)定性PyTorch實(shí)現(xiàn)optimizertorch.optim.Adam(rnn.parameters(),lr0.001)forepochinrange(num_epochs):forbatchindataloader:optimizer.zero_grad()outputsrnn(batch.inputs)losscriterion(outputs,batch.targets)loss.backward()optimizer.step()# Adam自動(dòng)處理參數(shù)更新為什么Adam適合RNN自適應(yīng)學(xué)習(xí)率能應(yīng)對(duì)RNN中不同參數(shù)的不同梯度規(guī)模動(dòng)量機(jī)制有助于穿越平坦區(qū)域?qū)W(xué)習(xí)率不太敏感3.2 截?cái)郆PTTTruncated BPTT問(wèn)題對(duì)于很長(zhǎng)的序列BPTT計(jì)算成本太高解決方案將長(zhǎng)序列截?cái)喑尚K算法seq_length1000# 原始序列很長(zhǎng)chunk_size50# 截?cái)嚅L(zhǎng)度f(wàn)orstartinrange(0,seq_length,chunk_size):endmin(startchunk_size,seq_length)# 只對(duì)這一塊做BPTTchunk_inputfull_sequence[start:end]chunk_targetfull_targets[start:end]# 前向傳播hrnn(chunk_input,h_prev.detach())# detach切斷梯度流losscriterion(h,chunk_target)# 反向傳播只在這個(gè)chunk內(nèi)loss.backward()optimizer.step()# 保留隱藏狀態(tài)用于下一個(gè)chunk但不保留梯度h_prevh.detach()關(guān)鍵點(diǎn)隱藏狀態(tài)在chunk間傳遞保持序列連續(xù)性梯度不在chunk間傳遞降低計(jì)算成本平衡chunk太小損失性能太大增加計(jì)算4. 工程方法4.1 高效訓(xùn)練技巧4.1.1 批處理與填充問(wèn)題不同序列長(zhǎng)度不同如何批處理解決方案填充Padding 掩碼Maskingimporttorchfromtorch.nn.utils.rnnimportpad_sequence,pack_padded_sequence,pad_packed_sequence# 原始序列長(zhǎng)度不同sequences[torch.tensor([1,2,3,4,5]),# 長(zhǎng)度 5torch.tensor([6,7]),# 長(zhǎng)度 2torch.tensor([8,9,10,11])# 長(zhǎng)度 4]# 方法1: 簡(jiǎn)單填充paddedpad_sequence(sequences,batch_firstTrue,padding_value0)# 結(jié)果:# [[1, 2, 3, 4, 5],# [6, 7, 0, 0, 0],# [8, 9, 10, 11, 0]]# 形狀: (3, 5) # 3個(gè)序列最大長(zhǎng)度5# 方法2: PackedSequence更高效lengthstorch.tensor([5,2,4])# 記錄真實(shí)長(zhǎng)度sorted_lengths,sorted_idxlengths.sort(descendingTrue)sorted_sequences[sequences[i]foriinsorted_idx]padded_sortedpad_sequence(sorted_sequences,batch_firstTrue)packedpack_padded_sequence(padded_sorted,sorted_lengths,batch_firstTrue)# RNN處理output,hiddenrnn(packed)# 解包unpacked,_pad_packed_sequence(output,batch_firstTrue)為什么PackedSequence更高效避免對(duì)填充部分做無(wú)用計(jì)算內(nèi)存占用更少訓(xùn)練速度更快4.1.2 雙向RNNBidirectional RNN動(dòng)機(jī)有些任務(wù)需要同時(shí)考慮過(guò)去和未來(lái)的信息結(jié)構(gòu)前向RNN: h_0 → h_1 → h_2 → h_3 ↓ ↓ ↓ 后向RNN: h_0 ← h_1 ← h_2 ← h_3 最終輸出: [h_forward; h_backward] 拼接數(shù)學(xué)公式h → t RNN forward ( x t , h → t ? 1 ) h ← t RNN backward ( x t , h ← t 1 ) h t [ h → t ; h ← t ] egin{aligned} overrightarrow{h}_t ext{RNN}_{ ext{forward}}(x_t, overrightarrow{h}_{t-1}) \ overleftarrow{h}_t ext{RNN}_{ ext{backward}}(x_t, overleftarrow{h}_{t1}) \ h_t [overrightarrow{h}_t; overleftarrow{h}_t] end{aligned}ht?ht?ht??RNNforward?(xt?,ht?1?)RNNbackward?(xt?,ht1?)[ht?;ht?]?維度變化# 單向RNNinput:(B,T,d)(2,3,10)hidden:(B,h)(2,20)output:(B,T,h)(2,3,20)# 雙向RNNinput:(B,T,d)(2,3,10)forward_hidden:(B,h)(2,20)backward_hidden:(B,h)(2,20)output:(B,T,2*h)(2,3,40)# 拼接后維度翻倍PyTorch實(shí)現(xiàn)rnnnn.RNN(input_size10,hidden_size20,num_layers1,bidirectionalTrue,batch_firstTrue)# 輸入: (B, T, d)output,hiddenrnn(input)# output: (B, T, 2*hidden_size)# hidden: (2, B, hidden_size) # 2表示前向和后向4.1.3 多層RNNStacked RNN結(jié)構(gòu)第2層: h2_0 → h2_1 → h2_2 ↑ ↑ ↑ 第1層: h1_0 → h1_1 → h1_2 ↑ ↑ ↑ 輸入: x_0 x_1 x_2維度變化2層RNN# 配置num_layers2input_size10hidden_size20batch_size2seq_length3# 第1層layer1_input:(2,3,10)# (B, T, input_size)layer1_output:(2,3,20)# (B, T, hidden_size)# 第2層第1層的輸出作為輸入layer2_input:(2,3,20)# 等于layer1_outputlayer2_output:(2,3,20)# (B, T, hidden_size)# 最終hidden state: (num_layers, B, hidden_size) (2, 2, 20)PyTorch實(shí)現(xiàn)rnnnn.RNN(input_size10,hidden_size20,num_layers2,batch_firstTrue)inputtorch.randn(2,3,10)# (B, T, input_size)h0torch.zeros(2,2,20)# (num_layers, B, hidden_size)output,hiddenrnn(input,h0)# output: (2, 3, 20) # 只輸出最后一層的結(jié)果# hidden: (2, 2, 20) # 所有層的最終隱藏狀態(tài)4.2 數(shù)值穩(wěn)定性4.2.1 權(quán)重初始化Xavier初始化適用于tanh激活W ~ U ( ? 6 n in n out , 6 n in n out ) W sim mathcal{U}left(-sqrt{frac{6}{n_{ ext{in}} n_{ ext{out}}}}, sqrt{frac{6}{n_{ ext{in}} n_{ ext{out}}}}
ight)W~U(?nin?nout?6??,nin?nout?6??)PyTorch實(shí)現(xiàn)forname,paraminrnn.named_parameters():ifweight_ihinname:# 輸入到隱藏層的權(quán)重nn.init.xavier_uniform_(param)elifweight_hhinname:# 隱藏層到隱藏層的權(quán)重nn.init.orthogonal_(param)# 正交初始化有助于緩解梯度消失elifbiasinname:nn.init.zeros_(param)4.2.2 Dropout正則化在RNN中應(yīng)用DropoutclassRNNWithDropout(nn.Module):def__init__(self,input_size,hidden_size,dropout0.5):super().__init__()self.rnnnn.RNN(input_size,hidden_size,batch_firstTrue)self.dropoutnn.Dropout(dropout)defforward(self,x):# 方法1: 在RNN輸出后應(yīng)用dropoutoutput,hiddenself.rnn(x)outputself.dropout(output)returnoutput,hidden注意不要在隱藏狀態(tài)的循環(huán)連接上使用dropout通常在RNN的輸出上或多層RNN的層間使用dropout4.3 硬件加速4.3.1 GPU優(yōu)化importtorch# 檢查GPU可用性devicetorch.device(cudaiftorch.cuda.is_available()elsecpu)# 模型和數(shù)據(jù)轉(zhuǎn)移到GPUrnnrnn.to(device)input_datainput_data.to(device)# cuDNN加速PyTorch自動(dòng)啟用torch.backends.cudnn.enabledTruetorch.backends.cudnn.benchmarkTrue# 自動(dòng)尋找最優(yōu)算法4.3.2 混合精度訓(xùn)練使用FP16加速訓(xùn)練fromtorch.cuda.ampimportautocast,GradScaler scalerGradScaler()forbatchindataloader:optimizer.zero_grad()# 前向傳播使用FP16withautocast():outputrnn(batch.input)losscriterion(output,batch.target)# 反向傳播時(shí)自動(dòng)縮放梯度scaler.scale(loss).backward()# 梯度裁剪scaler.unscale_(optimizer)torch.nn.utils.clip_grad_norm_(rnn.parameters(),max_norm1.0)# 參數(shù)更新scaler.step(optimizer)scaler.update()優(yōu)勢(shì)訓(xùn)練速度提升2-3倍顯存占用減少約50%在現(xiàn)代GPU上效果顯著5. 批判性思維技能5.1 RNN的局限性5.1.1 長(zhǎng)期依賴問(wèn)題問(wèn)題描述盡管理論上RNN可以捕捉長(zhǎng)距離依賴但實(shí)際上由于梯度消失很難學(xué)習(xí)距離超過(guò)10-20步的依賴關(guān)系。實(shí)驗(yàn)驗(yàn)證# 創(chuàng)建一個(gè)簡(jiǎn)單的復(fù)制任務(wù)# 任務(wù): 記住序列開始的符號(hào)在很久之后輸出defcreate_copy_task(seq_length,delay): seq_length: 序列長(zhǎng)度 delay: 需要記憶的時(shí)間步數(shù) # 輸入: [3, 7, 0, 0, 0, ..., 0, 9]# ↑ delay步 ↑# 記住這個(gè) 在這里輸出input_seq[random.randint(1,8)]# 需要記住的符號(hào)input_seq[0]*delay# 填充input_seq[9]# 觸發(fā)輸出的信號(hào)target_seq[0]*delay[input_seq[0]]# 最后才輸出記住的符號(hào)returninput_seq,target_seq# 測(cè)試標(biāo)準(zhǔn)RNNdelays[5,10,20,50,100]fordelayindelays:rnnSimpleRNN(input_size10,hidden_size50)accuracytrain_and_test(rnn,delay)print(fDelay{delay}, Accuracy{accuracy})# 預(yù)期結(jié)果:# Delay5, Accuracy0.95 ? 效果好# Delay10, Accuracy0.87 ? 還可以# Delay20, Accuracy0.45 ? 開始失敗# Delay50, Accuracy0.10 ? 完全失敗# Delay100, Accuracy0.10 ? 完全失敗結(jié)論標(biāo)準(zhǔn)RNN難以處理長(zhǎng)期依賴 → 需要LSTM/GRU5.1.2 并行化困難問(wèn)題RNN的計(jì)算是串行的時(shí)間步t tt必須等待時(shí)間步t ? 1 t-1t?1完成。# RNN: 必須串行h_0f(x_0,h_init)h_1f(x_1,h_0)# 必須等h_0算完h_2f(x_2,h_1)# 必須等h_1算完...# CNN或Transformer: 可以并行# 所有位置可以同時(shí)計(jì)算影響訓(xùn)練速度慢無(wú)法充分利用現(xiàn)代GPU的并行能力對(duì)長(zhǎng)序列尤其慢解決方向Transformer架構(gòu)完全并行并行RNN變體如Quasi-RNN5.2 何時(shí)使用RNN決策樹你的任務(wù)是什么 │ ├─ 序列建模 │ │ │ ├─ 序列很長(zhǎng)100 │ │ ├─ 是 → 考慮Transformer │ │ └─ 否 → 繼續(xù) │ │ │ ├─ 需要處理實(shí)時(shí)流數(shù)據(jù) │ │ ├─ 是 → RNN/LSTM/GRU保持隱藏狀態(tài) │ │ └─ 否 → 繼續(xù) │ │ │ ├─ 計(jì)算資源有限 │ │ ├─ 是 → GRU參數(shù)少 │ │ └─ 否 → LSTM效果更好 │ │ │ └─ 需要雙向信息 │ ├─ 是 → Bidirectional RNN │ └─ 否 → 單向RNN │ └─ 非序列任務(wù) → 不要用RNN考慮CNN/Transformer5.2.1 RNN適用場(chǎng)景? 適合使用RNN的情況實(shí)時(shí)序列處理語(yǔ)音識(shí)別、在線手寫識(shí)別中等長(zhǎng)度序列情感分析句子級(jí)別時(shí)間序列預(yù)測(cè)股票價(jià)格、天氣預(yù)報(bào)序列生成音樂生成、文本生成資源受限環(huán)境移動(dòng)設(shè)備、嵌入式系統(tǒng)? 不適合使用RNN的情況很長(zhǎng)序列500詞文檔分類 → 用Transformer完全并行任務(wù)圖像分類 → 用CNN不關(guān)心順序詞袋模型任務(wù) → 用MLP需要全局關(guān)注機(jī)器翻譯 → 用Transformer5.3 調(diào)試技巧5.3.1 檢查梯度# 檢查梯度是否消失/爆炸defcheck_gradients(model):total_norm0forname,paraminmodel.named_parameters():ifparam.gradisnotNone:param_normparam.grad.data.norm(2)total_normparam_norm.item()**2print(f{name}:{param_norm.item():.6f})total_normtotal_norm**0.5print(fTotal gradient norm:{total_norm:.6f})iftotal_norm1e-5:print(?? 警告: 梯度消失!)eliftotal_norm100:print(?? 警告: 梯度爆炸!)# 使用loss.backward()check_gradients(rnn)5.3.2 可視化隱藏狀態(tài)importmatplotlib.pyplotaspltdefvisualize_hidden_states(rnn,input_seq):可視化RNN的隱藏狀態(tài)演化hidden_states[]htorch.zeros(1,rnn.hidden_size)forx_tininput_seq:hrnn.step(x_t,h)hidden_states.append(h.detach().numpy())hidden_statesnp.array(hidden_states).squeeze()# 繪制熱圖plt.figure(figsize(12,6))plt.imshow(hidden_states.T,aspectauto,cmapviridis)plt.colorbar(labelActivation)plt.xlabel(Time Step)plt.ylabel(Hidden Unit)plt.title(RNN Hidden State Evolution)plt.show()# 觀察模式:# - 橫條紋: 某些單元持續(xù)激活好# - 快速變化: 響應(yīng)輸入好# - 全白/全黑: 飽和或死亡壞5.3.3 過(guò)擬合單個(gè)batch# 調(diào)試技巧: 先確保模型能過(guò)擬合單個(gè)樣本single_batchnext(iter(dataloader))foriinrange(1000):optimizer.zero_grad()outputrnn(single_batch.input)losscriterion(output,single_batch.target)loss.backward()optimizer.step()ifi%1000:print(fStep{i}, Loss:{loss.item():.6f})# 期望: loss應(yīng)該降到接近0# 如果不能 → 模型有bug或容量不足5.4 理論與實(shí)踐的差距5.4.1 理論能力 vs 實(shí)際表現(xiàn)理論RNN可以表示任意序列函數(shù)圖靈完備實(shí)踐受梯度消失限制需要大量數(shù)據(jù)訓(xùn)練困難啟示“理論上可能 ≠ 實(shí)際上可行”需要LSTM/GRU等改進(jìn)架構(gòu)5.4.2 超參數(shù)的影響實(shí)驗(yàn)固定架構(gòu)改變超參數(shù)# 測(cè)試不同隱藏層大小hidden_sizes[10,20,50,100,200]results[]forhinhidden_sizes:rnnSimpleRNN(input_size50,hidden_sizeh)test_acctrain(rnn)results.append(test_acc)# 觀察:# h10: underfitting (63% acc)# h20: still low (71% acc)# h50: good (87% acc) ← sweet spot# h100: good (88% acc)# h200: overfitting (85% acc) ← 太大反而下降經(jīng)驗(yàn)法則隱藏層大小: 通常在輸入維度的1-4倍學(xué)習(xí)率: 從0.001開始嘗試批次大小: 32-256取決于內(nèi)存梯度裁剪: 1.0-5.06. 附錄完整代碼示例6.1 從零實(shí)現(xiàn)RNN單元importnumpyasnpclassSimpleRNNCell:從零實(shí)現(xiàn)的RNN單元def__init__(self,input_size,hidden_size):# Xavier初始化self.W_xhnp.random.randn(hidden_size,input_size)*np.sqrt(2.0/input_size)self.W_hhnp.random.randn(hidden_size,hidden_size)*np.sqrt(2.0/hidden_size)self.b_hnp.zeros(hidden_size)# 輸出層假設(shè)二分類self.W_hynp.random.randn(2,hidden_size)*np.sqrt(2.0/hidden_size)self.b_ynp.zeros(2)defforward(self,x,h_prev): 前向傳播 x: (input_size,) h_prev: (hidden_size,) # h_t tanh(W_xh x W_hh h_prev b_h)h_nextnp.tanh(self.W_xh xself.W_hh h_prevself.b_h)# y_t W_hy h_t b_yyself.W_hy h_nextself.b_y# 保存中間值用于反向傳播self.cache(x,h_prev,h_next)returnh_next,ydefbackward(self,dh_next,dy): 反向傳播 dh_next: 從下一時(shí)間步傳來(lái)的梯度 dy: 當(dāng)前時(shí)間步輸出的梯度 x,h_prev,hself.cache# 輸出層梯度dW_hydy.reshape(-1,1) h.reshape(1,-1)db_ydy dhself.W_hy.T dydh_next# tanh的導(dǎo)數(shù)dtanh(1-h**2)*dh# 參數(shù)梯度dW_xhdtanh.reshape(-1,1) x.reshape(1,-1)dW_hhdtanh.reshape(-1,1) h_prev.reshape(1,-1)db_hdtanh# 傳遞給前一時(shí)間步的梯度dh_prevself.W_hh.T dtanhreturndh_prev,{W_xh:dW_xh,W_hh:dW_hh,b_h:db_h,W_hy:dW_hy,b_y:db_y}# 使用示例input_size,hidden_size10,20rnn_cellSimpleRNNCell(input_size,hidden_size)# 處理序列hnp.zeros(hidden_size)# 初始隱藏狀態(tài)sequence[np.random.randn(input_size)for_inrange(5)]forx_tinsequence:h,yrnn_cell.forward(x_t,h)print(fHidden state shape:{h.shape}, Output shape:{y.shape})6.2 PyTorch完整訓(xùn)練示例importtorchimporttorch.nnasnnimporttorch.optimasoptimfromtorch.utils.dataimportDataset,DataLoader# 1. 定義數(shù)據(jù)集 classTextDataset(Dataset):簡(jiǎn)單的文本分類數(shù)據(jù)集def__init__(self,texts,labels,vocab,max_length50):self.textstexts self.labelslabels self.vocabvocab self.max_lengthmax_lengthdef__len__(self):returnlen(self.texts)def__getitem__(self,idx):textself.texts[idx]labelself.labels[idx]# 文本轉(zhuǎn)索引indices[self.vocab.get(word,0)forwordintext.split()]# 截?cái)嗷蛱畛鋓flen(indices)self.max_length:indicesindices[:self.max_length]else:indices[0]*(self.max_length-len(indices))returntorch.tensor(indices),torch.tensor(label)# 2. 定義RNN模型 classTextRNN(nn.Module):def__init__(self,vocab_size,embed_dim,hidden_dim,output_dim,num_layers1,bidirectionalFalse,dropout0.5):super(TextRNN,self).__init__()# 詞嵌入層self.embeddingnn.Embedding(vocab_size,embed_dim,padding_idx0)# RNN層self.rnnnn.RNN(input_sizeembed_dim,hidden_sizehidden_dim,num_layersnum_layers,bidirectionalbidirectional,batch_firstTrue,dropoutdropoutifnum_layers1else0)# 全連接層fc_input_dimhidden_dim*2ifbidirectionalelsehidden_dim self.fcnn.Linear(fc_input_dim,output_dim)# Dropoutself.dropoutnn.Dropout(dropout)defforward(self,text):# text: (batch_size, seq_length)# 嵌入: (batch_size, seq_length, embed_dim)embeddedself.dropout(self.embedding(text))# RNN: output (batch_size, seq_length, hidden_dim * num_directions)# hidden (num_layers * num_directions, batch_size, hidden_dim)output,hiddenself.rnn(embedded)# 取最后一個(gè)時(shí)間步的輸出用于分類# 如果是雙向需要拼接前向和后向的最后隱藏狀態(tài)ifself.rnn.bidirectional:# hidden[-2, :, :] 是前向最后一層# hidden[-1, :, :] 是后向最后一層hiddentorch.cat([hidden[-2,:,:],hidden[-1,:,:]],dim1)else:hiddenhidden[-1,:,:]# 全連接: (batch_size, output_dim)outputself.fc(self.dropout(hidden))returnoutput# 3. 訓(xùn)練函數(shù) deftrain_epoch(model,dataloader,criterion,optimizer,device):model.train()total_loss0correct0total0forbatch_idx,(texts,labels)inenumerate(dataloader):texts,labelstexts.to(device),labels.to(device)# 前向傳播optimizer.zero_grad()outputsmodel(texts)losscriterion(outputs,labels)# 反向傳播loss.backward()# 梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(),max_norm1.0)# 參數(shù)更新optimizer.step()# 統(tǒng)計(jì)total_lossloss.item()_,predictedoutputs.max(1)totallabels.size(0)correctpredicted.eq(labels).sum().item()if(batch_idx1)%100:print(fBatch{batch_idx1}/{len(dataloader)}, fLoss:{loss.item():.4f}, fAcc:{100.*correct/total:.2f}%)returntotal_loss/len(dataloader),100.*correct/total# 4. 評(píng)估函數(shù) defevaluate(model,dataloader,criterion,device):model.eval()total_loss0correct0total0withtorch.no_grad():fortexts,labelsindataloader:texts,labelstexts.to(device),labels.to(device)outputsmodel(texts)losscriterion(outputs,labels)total_lossloss.item()_,predictedoutputs.max(1)totallabels.size(0)correctpredicted.eq(labels).sum().item()returntotal_loss/len(dataloader),100.*correct/total# 5. 主訓(xùn)練流程 defmain():# 設(shè)置設(shè)備devicetorch.device(cudaiftorch.cuda.is_available()elsecpu)print(fUsing device:{device})# 超參數(shù)VOCAB_SIZE10000EMBED_DIM100HIDDEN_DIM256OUTPUT_DIM2# 二分類NUM_LAYERS2BIDIRECTIONALTrueDROPOUT0.5BATCH_SIZE64LEARNING_RATE0.001NUM_EPOCHS10# 創(chuàng)建模型modelTextRNN(vocab_sizeVOCAB_SIZE,embed_dimEMBED_DIM,hidden_dimHIDDEN_DIM,output_dimOUTPUT_DIM,num_layersNUM_LAYERS,bidirectionalBIDIRECTIONAL,dropoutDROPOUT).to(device)print(f模型參數(shù)量:{sum(p.numel()forpinmodel.parameters()):,})# 損失函數(shù)和優(yōu)化器criterionnn.CrossEntropyLoss()optimizeroptim.Adam(model.parameters(),lrLEARNING_RATE)# 學(xué)習(xí)率調(diào)度器scheduleroptim.lr_scheduler.StepLR(optimizer,step_size5,gamma0.1)# 假設(shè)我們有訓(xùn)練和驗(yàn)證數(shù)據(jù)# train_loader DataLoader(train_dataset, batch_sizeBATCH_SIZE, shuffleTrue)# val_loader DataLoader(val_dataset, batch_sizeBATCH_SIZE)# 訓(xùn)練循環(huán)best_val_acc0forepochinrange(NUM_EPOCHS):print(f
{*50})print(fEpoch{epoch1}/{NUM_EPOCHS})print(f{*50})# 訓(xùn)練train_loss,train_acctrain_epoch(model,train_loader,criterion,optimizer,device)# 驗(yàn)證val_loss,val_accevaluate(model,val_loader,criterion,device)# 更新學(xué)習(xí)率scheduler.step()print(f
Train Loss:{train_loss:.4f}, Train Acc:{train_acc:.2f}%)print(fVal Loss:{val_loss:.4f}, Val Acc:{val_acc:.2f}%)# 保存最佳模型ifval_accbest_val_acc:best_val_accval_acc torch.save(model.state_dict(),best_rnn_model.pth)print(? Saved best model)print(f
訓(xùn)練完成! 最佳驗(yàn)證準(zhǔn)確率:{best_val_acc:.2f}%)# if __name__ __main__:# main()6.3 維度追蹤工具classDimensionTracker:輔助追蹤RNN中的維度變化staticmethoddefprint_shape(tensor,name):打印張量形狀ifisinstance(tensor,torch.Tensor):print(f{name:20s}:{str(tuple(tensor.shape)):20s}dtype{tensor.dtype})else:print(f{name:20s}:{tensor})staticmethoddeftrace_rnn_forward(rnn_module,input_tensor,hiddenNone):追蹤RNN前向傳播的所有維度print(
*60)print(RNN Forward Pass Dimension Trace)print(*60)# 輸入DimensionTracker.print_shape(input_tensor,Input)# 模型參數(shù)print(
Model Parameters:)forname,paraminrnn_module.named_parameters():DimensionTracker.print_shape(param,name)# 前向傳播print(
Forward Propagation:)ifhiddenisnotNone:DimensionTracker.print_shape(hidden,Initial Hidden)output,hiddenrnn_module(input_tensor,hidden)else:output,hiddenrnn_module(input_tensor)# 輸出print(
Outputs:)DimensionTracker.print_shape(output,Output)DimensionTracker.print_shape(hidden,Final Hidden)print(*60
)returnoutput,hidden# 使用示例rnnnn.RNN(input_size10,hidden_size20,num_layers2,bidirectionalTrue,batch_firstTrue)input_tensortorch.randn(3,5,10)# (batch, seq_len, input_size)output,hiddenDimensionTracker.trace_rnn_forward(rnn,input_tensor)# 輸出示例:# # RNN Forward Pass Dimension Trace# # Input : (3, 5, 10) dtypetorch.float32## Model Parameters:# weight_ih_l0 : (20, 10) dtypetorch.float32# weight_hh_l0 : (20, 20) dtypetorch.float32# bias_ih_l0 : (20,) dtypetorch.float32# bias_hh_l0 : (20,) dtypetorch.float32# ...## Forward Propagation:## Outputs:# Output : (3, 5, 40) dtypetorch.float32# Final Hidden : (4, 3, 20) dtypetorch.float32# 6.4 可視化工具importmatplotlib.pyplotaspltimportseabornassnsdefvisualize_attention_weights(attention_weights,input_words,output_words):可視化注意力權(quán)重適用于seq2seq with attentionplt.figure(figsize(10,8))sns.heatmap(attention_weights,xticklabelsinput_words,yticklabelsoutput_words,cmapBlues,annotTrue,fmt.2f)plt.xlabel(Input Words)plt.ylabel(Output Words)plt.title(Attention Weights Visualization)plt.tight_layout()plt.show()defplot_training_curves(train_losses,val_losses,train_accs,val_accs):繪制訓(xùn)練曲線fig,(ax1,ax2)plt.subplots(1,2,figsize(15,5))# 損失曲線ax1.plot(train_losses,labelTrain Loss,markero)ax1.plot(val_losses,labelVal Loss,markers)ax1.set_xlabel(Epoch)ax1.set_ylabel(Loss)ax1.set_title(Training and Validation Loss)ax1.legend()ax1.grid(True)# 準(zhǔn)確率曲線ax2.plot(train_accs,labelTrain Acc,markero)ax2.plot(val_accs,labelVal Acc,markers)ax2.set_xlabel(Epoch)ax2.set_ylabel(Accuracy (%))ax2.set_title(Training and Validation Accuracy)ax2.legend()ax2.grid(True)plt.tight_layout()plt.show()總結(jié)動(dòng)機(jī): RNN通過(guò)引入記憶機(jī)制處理序列數(shù)據(jù)解決了傳統(tǒng)神經(jīng)網(wǎng)絡(luò)無(wú)法捕捉時(shí)序依賴的問(wèn)題數(shù)學(xué)基礎(chǔ):核心公式:h t tanh ? ( W h h h t ? 1 W x h x t b h ) h_t anh(W_{hh} h_{t-1} W_{xh} x_t b_h)ht?tanh(Whh?ht?1?Wxh?xt?bh?)關(guān)鍵是理解維度變化和數(shù)據(jù)流動(dòng)BPTT算法用于訓(xùn)練優(yōu)化算法:梯度裁剪防止梯度爆炸Adam優(yōu)化器適合RNN截?cái)郆PTT處理長(zhǎng)序列工程方法:PackedSequence高效處理變長(zhǎng)序列雙向RNN和多層RNN提升能力混合精度訓(xùn)練加速局限性:長(zhǎng)期依賴問(wèn)題 → LSTM/GRU并行化困難 → Transformer