RNN(Recurrent Neural Network,循環神經網絡)家族詳解(RNN,LSTM,GRU)

文章目錄

    • 一、RNN基礎:序列建模的核心思想
      • 1.1 RNN的本質與核心機制
      • 1.2 應用場景與結構分類
    • 二、傳統RNN:序列模型的起點
      • 2.1 內部結構與數學表達
      • 2.2 計算示例
      • 2.3 RNN在Pytorch中的API
      • 2.4 代碼示例
      • 2.5 優缺點與梯度問題
    • 三、LSTM:門控機制破解長期依賴
      • 3.1 四大門控機制詳解
      • 3.2 "Bob"案例的LSTM完整計算示例
      • 3.3 LSTM在Pytorch中的API
      • 3.4 代碼示例
      • 3.5 門控機制的數學本質
    • 四、GRU:LSTM的輕量級進化
      • 4.1 雙門控簡化結構
      • 4.2 "Bob"案例的GRU完整計算過程
      • 4.3 GRU在Pytorch中的API
      • 3.4 代碼示例
    • 五、三大模型的對比與實踐選擇
      • 5.1 核心指標對比
      • 5.2 適用場景建議
      • 5.3 要點

循環神經網絡(RNN)作為處理序列數據的核心模型,在自然語言處理、時間序列分析等領域發揮著關鍵作用。本文將系統梳理傳統RNN、LSTM和GRU的內部機制、數學表達與實踐應用,通過統一案例對比三者的計算過程,幫助讀者深入理解序列模型的進化脈絡。

一、RNN基礎:序列建模的核心思想

在這里插入圖片描述

1.1 RNN的本質與核心機制

RNN(Recurrent Neural Network)的核心創新在于"循環記憶"機制——將上一時間步的隱藏狀態與當前輸入結合,形成對序列依賴關系的建模能力。其本質是通過參數共享實現對時間維度的特征提取,數學上表現為:

h t = f ( W ? [ x t , h t ? 1 ] + b ) h_t = f(W \cdot [x_t, h_{t-1}] + b) ht?=f(W?[xt?,ht?1?]+b)

  • x t x_t xt?:當前時間步輸入向量
  • h t ? 1 h_{t-1} ht?1?:上一時間步隱藏狀態
  • f f f:激活函數(通常為tanh或sigmoid)

這種結構使得RNN能夠捕捉序列中的短期依賴,例如判斷"我愛吃蘋果"中"蘋果"的詞性需依賴前文"吃"的動作。

1.2 應用場景與結構分類

RNN按輸入輸出結構可分為四類:

  • N vs N:輸入輸出等長,適用于語音識別中的幀級標注
  • N vs 1:序列輸入→單一輸出,典型如文本分類
  • 1 vs N:單一輸入→序列輸出,常用于圖片生成描述
  • N vs M:seq2seq架構,輸入輸出長度不限,是機器翻譯的基礎

二、傳統RNN:序列模型的起點

結構圖
在這里插入圖片描述 在這里插入圖片描述

2.1 內部結構與數學表達

傳統RNN的計算流程可拆解為:

  1. 輸入拼接: [ x t , h t ? 1 ] [x_t, h_{t-1}] [xt?,ht?1?]
  2. 線性變換: W ? [ x t , h t ? 1 ] + b W \cdot [x_t, h_{t-1}] + b W?[xt?,ht?1?]+b
  3. 激活輸出: h t = tanh ? ( ? ) h_t = \tanh(\cdot) ht?=tanh(?)

以一個3維輸入、4維隱藏狀態的RNN為例,其參數矩陣為:

  • 輸入權重 W i h ∈ R 4 × 3 W_{ih} \in \mathbb{R}^{4 \times 3} Wih?R4×3
  • 隱藏權重 W h h ∈ R 4 × 4 W_{hh} \in \mathbb{R}^{4 \times 4} Whh?R4×4
  • 偏置 b ∈ R 4 b \in \mathbb{R}^4 bR4

2.2 計算示例

人名"Bob"的特征提取
假設:

  • 字符編碼:‘B’=[0.1,0,0], ‘o’=[0,0.1,0], ‘b’=[0,0,0.1]
  • RNN參數: W i h = [ [ 1 , 0 , 0 ] , [ 0 , 1 , 0 ] , [ 0 , 0 , 1 ] , [ 1 , 1 , 1 ] ] W_{ih} = [[1,0,0],[0,1,0],[0,0,1],[1,1,1]] Wih?=[[1,0,0],[0,1,0],[0,0,1],[1,1,1]](簡化示例)
  • W h h = [ [ 1 , 0 , 0 , 0 ] , [ 0 , 1 , 0 , 0 ] , [ 0 , 0 , 1 , 0 ] , [ 0 , 0 , 0 , 1 ] ] W_{hh} = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]] Whh?=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]

計算步驟:

  1. 時間步1:輸入’B’
    h 1 = tanh ? ( W i h ? ′ B ′ + W h h ? h 0 ) = tanh ? ( [ 0.1 , 0 , 0 , 0.1 ] ) h_1 = \tanh(W_{ih} \cdot 'B' + W_{hh} \cdot h_0) = \tanh([0.1, 0, 0, 0.1]) h1?=tanh(Wih??B+Whh??h0?)=tanh([0.1,0,0,0.1])
    h 1 = [ 0.099 , 0 , 0 , 0.099 ] h_1 = [0.099, 0, 0, 0.099] h1?=[0.099,0,0,0.099](假設h0全0)

  2. 時間步2:輸入’o’
    h 2 = tanh ? ( W i h ? ′ o ′ + W h h ? h 1 ) h_2 = \tanh(W_{ih} \cdot 'o' + W_{hh} \cdot h_1) h2?=tanh(Wih??o+Whh??h1?)
    = tanh ? ( [ 0 , 0.1 , 0 , 0.1 + 0.099 ] ) = [ 0 , 0.099 , 0 , 0.197 ] = \tanh([0, 0.1, 0, 0.1+0.099]) = [0, 0.099, 0, 0.197] =tanh([0,0.1,0,0.1+0.099])=[0,0.099,0,0.197]

  3. 時間步3:輸入’b’
    h 3 = tanh ? ( [ 0 , 0 , 0.1 , 0.1 + 0.197 ] ) = [ 0 , 0 , 0.099 , 0.292 ] h_3 = \tanh([0, 0, 0.1, 0.1+0.197]) = [0, 0, 0.099, 0.292] h3?=tanh([0,0,0.1,0.1+0.197])=[0,0,0.099,0.292]

最終隱藏狀態 h 3 h_3 h3?已經包含"Bob"的所有信息,即為"Bob"的序列特征表示。

2.3 RNN在Pytorch中的API

  1. RNN類定義與核心參數
torch.nn.RNN(input_size,           # 輸入特征維度hidden_size,          # 隱藏狀態維度num_layers=1,         # 堆疊的RNN層數nonlinearity='tanh',  # 非線性激活函數 'tanh' 或 'relu'bias=True,            # 是否使用偏置batch_first=False,    # 輸入格式是否為(batch, seq, feature)dropout=0,            # Dropout概率bidirectional=False   # 是否為雙向RNN
)
  1. 輸入與輸出格式

    輸入參數:

    • input:輸入序列,形狀為(seq_len, batch, input_size)(默認)或(batch, seq_len, input_size)batch_first=True
    • h 0 h_0 h0?:初始隱藏狀態,形狀為(num_layers * num_directions, batch, hidden_size)

    輸出參數:

    • output:所有時間步的隱藏狀態,形狀為(seq_len, batch, hidden_size * num_directions)
    • h n h_n hn?:最后一個時間步的隱藏狀態,形狀同$h_0$
  2. 關鍵屬性與方法

    權重矩陣:

    • w e i g h t i h l [ k ] weight_ih_l[k] weighti?hl?[k]:第k層的輸入到隱藏的權重
    • w e i g h t h h l [ k ] weight_hh_l[k] weighth?hl?[k]:第k層的隱藏到隱藏的權重
    • b i a s i h l [ k ] bias_ih_l[k] biasi?hl?[k] b i a s h h l [ k ] bias_hh_l[k] biash?hl?[k]:對應偏置

    前向傳播方法:

output, h_n = rnn(input, h_0)

2.4 代碼示例

  1. 基本用法
import torch
import torch.nn as nn# 創建RNN模型
rnn = nn.RNN(input_size=10,      # 輸入特征維度hidden_size=20,     # 隱藏狀態維度num_layers=2,       # 2層RNN堆疊batch_first=True,   # 使用(batch, seq, feature)格式bidirectional=True  # 雙向RNN
)# 準備輸入
batch_size = 3
seq_len = 5
x = torch.randn(batch_size, seq_len, 10)  # 輸入序列# 初始化隱藏狀態(可選)
h0 = torch.zeros(2*2, batch_size, 20)  # 2層 * 雙向# 前向傳播
output, hn = rnn(x, h0)# 輸出形狀分析
print("Output shape:", output.shape)      # (3, 5, 40)  [batch, seq, hidden*2]
print("Final hidden shape:", hn.shape)    # (4, 3, 20)  [layers*directions, batch, hidden]
  1. 獲取最后時間步的隱藏狀態
# 方法1:從output中獲取
last_output = output[:, -1, :]  # (batch, hidden*directions)# 方法2:從hn中獲取
last_hidden = hn[-2:] if rnn.bidirectional else hn[-1]  # 雙向時需拼接兩個方向
last_hidden = torch.cat([last_hidden[0], last_hidden[1]], dim=1) if rnn.bidirectional else last_hidden

2.5 優缺點與梯度問題

  • 優勢:結構簡單,參數量少,短序列計算效率高
  • 致命缺陷:長序列中梯度消失嚴重,如:
    梯度連乘公式: ? = ∏ i = 1 n σ ′ ( z i ) ? w i \nabla = \prod_{i=1}^n \sigma'(z_i) \cdot w_i ?=i=1n?σ(zi?)?wi?
    w i < 1 w_i < 1 wi?<1時,連乘導致梯度趨近于0,無法更新遠層參數

三、LSTM:門控機制破解長期依賴

在這里插入圖片描述
在這里插入圖片描述

3.1 四大門控機制詳解

LSTM通過引入門控系統,將傳統RNN的單一隱藏狀態拆分為:

  • 細胞狀態C:長期記憶載體
  • 隱藏狀態h:短期特征表示

核心公式組

  1. 遺忘門:決定丟棄歷史信息

    • 功能:決定丟棄細胞狀態中的哪些歷史信息。
    • 計算過程
      • 輸入當前輸入 x t x_t xt? 和上一時刻隱藏狀態 h t ? 1 h_{t-1} ht?1?,拼接后通過全連接層
      • f t f_t ft? 是0到1之間的門值,1表示“完全保留”,0表示“完全遺忘”。

    在這里插入圖片描述

  2. 輸入門:篩選新信息

    • 功能:決定當前輸入的新信息中哪些需要存儲到細胞狀態。
    • 計算過程
      • 生成輸入門門值 i t i_t it?(類似遺忘門,通過sigmoid激活):
      • 生成候選細胞狀態 C ~ t \tilde{C}_t C~t?(通過tanh激活):
        在這里插入圖片描述
  3. 細胞狀態更新

    • 功能:存儲長期記憶,通過門控機制更新。
    • 更新過程
      • f t ? C t ? 1 f_t * C_{t-1} ft??Ct?1?:遺忘門作用于舊細胞狀態,丟棄部分歷史信息;
      • i t ? C ~ t i_t *\tilde{C}_t it??C~t?:輸入門篩選新信息并與候選狀態結合。

    在這里插入圖片描述

  4. 輸出門:生成當前隱藏狀態

    • 功能:決定細胞狀態中的哪些信息作為當前隱藏狀態輸出。
    • 計算過程
      • 生成輸出門門值 o t o_t ot?
      • 細胞狀態通過tanh激活后,與輸出門值相乘得到隱藏狀態
        在這里插入圖片描述

3.2 "Bob"案例的LSTM完整計算示例

為便于與RNN對比,我們保持輸入維度、隱藏狀態維度一致,并使用相似的參數設置:

假設條件:

  • 輸入維度=3,隱藏狀態維度=4
  • 字符編碼:‘B’=[0.1,0,0], ‘o’=[0,0.1,0], ‘b’=[0,0,0.1]
  • LSTM參數(簡化后):
    W_f = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    W_i = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    W_c = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    W_o = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    
    (注:每個權重矩陣實際為4x7,因拼接 h t ? 1 h_{t-1} ht?1?(4維)和 x t x_t xt?(3維))

詳細計算過程:

時間步1:輸入 ‘B’ = [0.1, 0, 0]

  1. 遺忘門計算:
    f 1 = σ ( W f ? [ h 0 , ′ B ′ ] + b f ) f_1 = \sigma(W_f \cdot [h_0, 'B'] + b_f) f1?=σ(Wf??[h0?,B]+bf?)
    假設 b f = [ 0 , 0 , 0 , 0 ] b_f=[0,0,0,0] bf?=[0,0,0,0],則:
    W f ? [ h 0 , ′ B ′ ] = [ [ 1 , 0 , 0 , 1 , 0 , 0 , 0 ] , . . . ] ? [ 0 , 0 , 0 , 0 , 0.1 , 0 , 0 ] T = [ 0.1 , 0 , 0 , 0 ] W_f \cdot [h_0, 'B'] = [[1,0,0,1,0,0,0], ...] \cdot [0,0,0,0,0.1,0,0]^T = [0.1, 0, 0, 0] Wf??[h0?,B]=[[1,0,0,1,0,0,0],...]?[0,0,0,0,0.1,0,0]T=[0.1,0,0,0]
    f 1 = σ ( [ 0.1 , 0 , 0 , 0 ] ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] f_1 = \sigma([0.1, 0, 0, 0]) = [0.525, 0.5, 0.5, 0.5] f1?=σ([0.1,0,0,0])=[0.525,0.5,0.5,0.5]

  2. 輸入門計算:
    i 1 = σ ( W i ? [ h 0 , ′ B ′ ] + b i ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] i_1 = \sigma(W_i \cdot [h_0, 'B'] + b_i) = [0.525, 0.5, 0.5, 0.5] i1?=σ(Wi??[h0?,B]+bi?)=[0.525,0.5,0.5,0.5]
    C ~ 1 = tanh ? ( W c ? [ h 0 , ′ B ′ ] + b c ) = tanh ? ( [ 0.1 , 0 , 0 , 0 ] ) = [ 0.099 , 0 , 0 , 0 ] \tilde{C}_1 = \tanh(W_c \cdot [h_0, 'B'] + b_c) = \tanh([0.1, 0, 0, 0]) = [0.099, 0, 0, 0] C~1?=tanh(Wc??[h0?,B]+bc?)=tanh([0.1,0,0,0])=[0.099,0,0,0]

  3. 細胞狀態更新:
    C 1 = f 1 ⊙ C 0 + i 1 ⊙ C ~ 1 C_1 = f_1 \odot C_0 + i_1 \odot \tilde{C}_1 C1?=f1?C0?+i1?C~1?
    = [ 0.525 , 0.5 , 0.5 , 0.5 ] ⊙ [ 0 , 0 , 0 , 0 ] + [ 0.525 , 0.5 , 0.5 , 0.5 ] ⊙ [ 0.099 , 0 , 0 , 0 ] = [0.525, 0.5, 0.5, 0.5] \odot [0,0,0,0] + [0.525, 0.5, 0.5, 0.5] \odot [0.099, 0, 0, 0] =[0.525,0.5,0.5,0.5][0,0,0,0]+[0.525,0.5,0.5,0.5][0.099,0,0,0]
    = [ 0.052 , 0 , 0 , 0 ] = [0.052, 0, 0, 0] =[0.052,0,0,0]

  4. 輸出門與隱藏狀態:
    o 1 = σ ( W o ? [ h 0 , ′ B ′ ] + b o ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] o_1 = \sigma(W_o \cdot [h_0, 'B'] + b_o) = [0.525, 0.5, 0.5, 0.5] o1?=σ(Wo??[h0?,B]+bo?)=[0.525,0.5,0.5,0.5]
    h 1 = o 1 ⊙ tanh ? ( C 1 ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] ⊙ [ 0.052 , 0 , 0 , 0 ] = [ 0.027 , 0 , 0 , 0 ] h_1 = o_1 \odot \tanh(C_1) = [0.525, 0.5, 0.5, 0.5] \odot [0.052, 0, 0, 0] = [0.027, 0, 0, 0] h1?=o1?tanh(C1?)=[0.525,0.5,0.5,0.5][0.052,0,0,0]=[0.027,0,0,0]

時間步2:輸入 ‘o’ = [0, 0.1, 0]

  1. 遺忘門計算:
    W f ? [ h 1 , ′ o ′ ] = [ [ 1 , 0 , 0 , 1 , 0 , 0 , 0 ] , . . . ] ? [ 0.027 , 0 , 0 , 0 , 0 , 0.1 , 0 ] T = [ 0.027 , 0.1 , 0 , 0 ] W_f \cdot [h_1, 'o'] = [[1,0,0,1,0,0,0], ...] \cdot [0.027,0,0,0,0,0.1,0]^T = [0.027, 0.1, 0, 0] Wf??[h1?,o]=[[1,0,0,1,0,0,0],...]?[0.027,0,0,0,0,0.1,0]T=[0.027,0.1,0,0]
    f 2 = σ ( [ 0.027 , 0.1 , 0 , 0 ] ) = [ 0.507 , 0.525 , 0.5 , 0.5 ] f_2 = \sigma([0.027, 0.1, 0, 0]) = [0.507, 0.525, 0.5, 0.5] f2?=σ([0.027,0.1,0,0])=[0.507,0.525,0.5,0.5]

  2. 輸入門計算:
    i 2 = σ ( [ 0.027 , 0.1 , 0 , 0 ] ) = [ 0.507 , 0.525 , 0.5 , 0.5 ] i_2 = \sigma([0.027, 0.1, 0, 0]) = [0.507, 0.525, 0.5, 0.5] i2?=σ([0.027,0.1,0,0])=[0.507,0.525,0.5,0.5]
    C ~ 2 = tanh ? ( [ 0.027 , 0.1 , 0 , 0 ] ) = [ 0.027 , 0.099 , 0 , 0 ] \tilde{C}_2 = \tanh([0.027, 0.1, 0, 0]) = [0.027, 0.099, 0, 0] C~2?=tanh([0.027,0.1,0,0])=[0.027,0.099,0,0]

  3. 細胞狀態更新:
    C 2 = f 2 ⊙ C 1 + i 2 ⊙ C ~ 2 C_2 = f_2 \odot C_1 + i_2 \odot \tilde{C}_2 C2?=f2?C1?+i2?C~2?
    = [ 0.026 , 0 , 0 , 0 ] + [ 0.014 , 0.052 , 0 , 0 ] = [ 0.04 , 0.052 , 0 , 0 ] = [0.026, 0, 0, 0] + [0.014, 0.052, 0, 0] = [0.04, 0.052, 0, 0] =[0.026,0,0,0]+[0.014,0.052,0,0]=[0.04,0.052,0,0]

  4. 輸出門與隱藏狀態:
    o 2 = σ ( [ 0.027 , 0.1 , 0 , 0 ] ) = [ 0.507 , 0.525 , 0.5 , 0.5 ] o_2 = \sigma([0.027, 0.1, 0, 0]) = [0.507, 0.525, 0.5, 0.5] o2?=σ([0.027,0.1,0,0])=[0.507,0.525,0.5,0.5]
    h 2 = o 2 ⊙ tanh ? ( C 2 ) = [ 0.507 , 0.525 , 0.5 , 0.5 ] ⊙ [ 0.04 , 0.052 , 0 , 0 ] = [ 0.02 , 0.027 , 0 , 0 ] h_2 = o_2 \odot \tanh(C_2) = [0.507, 0.525, 0.5, 0.5] \odot [0.04, 0.052, 0, 0] = [0.02, 0.027, 0, 0] h2?=o2?tanh(C2?)=[0.507,0.525,0.5,0.5][0.04,0.052,0,0]=[0.02,0.027,0,0]

時間步3:輸入 ‘b’ = [0, 0, 0.1]

  1. 遺忘門計算:
    W f ? [ h 2 , ′ b ′ ] = [ 0.02 , 0.027 , 0.1 , 0 ] W_f \cdot [h_2, 'b'] = [0.02, 0.027, 0.1, 0] Wf??[h2?,b]=[0.02,0.027,0.1,0]
    f 3 = σ ( [ 0.02 , 0.027 , 0.1 , 0 ] ) = [ 0.505 , 0.507 , 0.525 , 0.5 ] f_3 = \sigma([0.02, 0.027, 0.1, 0]) = [0.505, 0.507, 0.525, 0.5] f3?=σ([0.02,0.027,0.1,0])=[0.505,0.507,0.525,0.5]

  2. 輸入門計算:
    i 3 = σ ( [ 0.02 , 0.027 , 0.1 , 0 ] ) = [ 0.505 , 0.507 , 0.525 , 0.5 ] i_3 = \sigma([0.02, 0.027, 0.1, 0]) = [0.505, 0.507, 0.525, 0.5] i3?=σ([0.02,0.027,0.1,0])=[0.505,0.507,0.525,0.5]
    C ~ 3 = tanh ? ( [ 0.02 , 0.027 , 0.1 , 0 ] ) = [ 0.02 , 0.027 , 0.099 , 0 ] \tilde{C}_3 = \tanh([0.02, 0.027, 0.1, 0]) = [0.02, 0.027, 0.099, 0] C~3?=tanh([0.02,0.027,0.1,0])=[0.02,0.027,0.099,0]

  3. 細胞狀態更新:
    C 3 = f 3 ⊙ C 2 + i 3 ⊙ C ~ 3 C_3 = f_3 \odot C_2 + i_3 \odot \tilde{C}_3 C3?=f3?C2?+i3?C~3?
    = [ 0.02 , 0.026 , 0 , 0 ] + [ 0.01 , 0.014 , 0.052 , 0 ] = [ 0.03 , 0.04 , 0.052 , 0 ] = [0.02, 0.026, 0, 0] + [0.01, 0.014, 0.052, 0] = [0.03, 0.04, 0.052, 0] =[0.02,0.026,0,0]+[0.01,0.014,0.052,0]=[0.03,0.04,0.052,0]

  4. 輸出門與隱藏狀態:
    o 3 = σ ( [ 0.02 , 0.027 , 0.1 , 0 ] ) = [ 0.505 , 0.507 , 0.525 , 0.5 ] o_3 = \sigma([0.02, 0.027, 0.1, 0]) = [0.505, 0.507, 0.525, 0.5] o3?=σ([0.02,0.027,0.1,0])=[0.505,0.507,0.525,0.5]
    h 3 = o 3 ⊙ tanh ? ( C 3 ) = [ 0.015 , 0.02 , 0.027 , 0 ] h_3 = o_3 \odot \tanh(C_3) = [0.015, 0.02, 0.027, 0] h3?=o3?tanh(C3?)=[0.015,0.02,0.027,0]

最終結果對比

模型"Bob"的特征表示(最終隱藏狀態)
RNN[0, 0, 0.099, 0.292]
LSTM[0.015, 0.02, 0.027, 0]

關鍵差異分析:

  1. 信息保留方式

    • RNN直接累加歷史信息,導致后期輸入權重過大(如’b’的影響占主導)
    • LSTM通過門控機制平衡了各字符的影響,保留了更均衡的特征表示
  2. 梯度傳遞能力

    • RNN的梯度依賴 tanh ? \tanh tanh導數(最大值為1),易衰減
    • LSTM的細胞狀態通過 f t f_t ft?(接近1)傳遞梯度,避免消失

3.3 LSTM在Pytorch中的API

  1. LSTM類定義與核心參數
torch.nn.LSTM(input_size,           # 輸入特征維度hidden_size,          # 隱藏狀態維度num_layers=1,         # 堆疊的LSTM層數bias=True,            # 是否使用偏置batch_first=False,    # 輸入格式是否為(batch, seq, feature)dropout=0,            # Dropout概率bidirectional=False   # 是否為雙向LSTM
)
  1. 輸入與輸出格式

    輸入參數:

    • input:輸入序列,形狀為(seq_len, batch, input_size)(默認)或(batch, seq_len, input_size)batch_first=True
    • h 0 h_0 h0?:初始隱藏狀態,形狀為(num_layers * num_directions, batch, hidden_size)
    • c 0 c_0 c0?:初始細胞狀態,形狀為(num_layers * num_directions, batch, hidden_size)

    輸出參數:

    • output:所有時間步的隱藏狀態,形狀為(seq_len, batch, hidden_size * num_directions)
    • h n h_n hn?:最后一個時間步的隱藏狀態,形狀同h_0
    • c n c_n cn?:最后一個時間步的細胞狀態,形狀同c_0
  2. 關鍵屬性與方法

    權重矩陣:

    • w e i g h t i h l [ k ] weight_ih_l[k] weighti?hl?[k]:第k層的輸入到隱藏的權重(4個門合并)
    • w e i g h t h h l [ k ] weight_hh_l[k] weighth?hl?[k]:第k層的隱藏到隱藏的權重(4個門合并)
    • b i a s i h l [ k ] bias_ih_l[k] biasi?hl?[k] b i a s h h l [ k ] bias_hh_l[k] biash?hl?[k]:對應偏置
  3. 前向傳播方法

output, (h_n, c_n) = lstm(input, (h_0, c_0))

3.4 代碼示例

  1. 基本用法
import torch
import torch.nn as nn# 創建LSTM模型
lstm = nn.LSTM(input_size=10,      # 輸入特征維度hidden_size=20,     # 隱藏狀態維度num_layers=2,       # 2層LSTM堆疊batch_first=True,   # 使用(batch, seq, feature)格式bidirectional=True  # 雙向LSTM
)# 準備輸入
batch_size = 3
seq_len = 5
x = torch.randn(batch_size, seq_len, 10)  # 輸入序列# 初始化隱藏狀態和細胞狀態(可選)
h0 = torch.zeros(2*2, batch_size, 20)  # 2層 * 雙向
c0 = torch.zeros(2*2, batch_size, 20)# 前向傳播
output, (hn, cn) = lstm(x, (h0, c0))# 輸出形狀分析
print("Output shape:", output.shape)      # (3, 5, 40)  [batch, seq, hidden*2]
print("Final hidden shape:", hn.shape)    # (4, 3, 20)  [layers*directions, batch, hidden]
print("Final cell shape:", cn.shape)      # (4, 3, 20)
  1. 獲取最后時間步的隱藏狀態
# 方法1:從output中獲取
last_output = output[:, -1, :]  # (batch, hidden*directions)# 方法2:從hn中獲取
last_hidden = hn[-2:] if lstm.bidirectional else hn[-1]  # 雙向時需拼接兩個方向
last_hidden = torch.cat([last_hidden[0], last_hidden[1]], dim=1) if lstm.bidirectional else last_hidden

3.5 門控機制的數學本質

LSTM通過線性組合( C t = f t C t ? 1 + i t C ~ t C_t = f_tC_{t-1} + i_t\tilde{C}_t Ct?=ft?Ct?1?+it?C~t?)實現梯度的"直連"傳播,避免了傳統RNN的連乘衰減,數學上表現為:
? C t ? C t ? 1 = f t \frac{\partial C_t}{\partial C_{t-1}} = f_t ?Ct?1??Ct??=ft?
f t f_t ft?接近1時,梯度可近乎無損地傳遞至遠層,這是LSTM解決長期依賴的核心。

四、GRU:LSTM的輕量級進化

在這里插入圖片描述
在這里插入圖片描述

4.1 雙門控簡化結構

GRU將LSTM的四門結構簡化為:

  1. 更新門:控制歷史信息保留比例
    z t = σ ( W z ? [ h t ? 1 , x t ] + b z ) z_t = \sigma(W_z \cdot [h_{t-1}, x_t] + b_z) zt?=σ(Wz??[ht?1?,xt?]+bz?)
  2. 重置門:控制歷史信息遺忘程度
    r t = σ ( W r ? [ h t ? 1 , x t ] + b r ) r_t = \sigma(W_r \cdot [h_{t-1}, x_t] + b_r) rt?=σ(Wr??[ht?1?,xt?]+br?)

核心公式:

  • 候選狀態: h ~ t = tanh ? ( W ? [ r t ⊙ h t ? 1 , x t ] + b ) \tilde{h}_t = \tanh(W \cdot [r_t \odot h_{t-1}, x_t] + b) h~t?=tanh(W?[rt?ht?1?,xt?]+b)
  • 狀態更新: h t = ( 1 ? z t ) ⊙ h t ? 1 + z t ⊙ h ~ t h_t = (1-z_t) \odot h_{t-1} + z_t \odot \tilde{h}_t ht?=(1?zt?)ht?1?+zt?h~t?

4.2 "Bob"案例的GRU完整計算過程

為便于與RNN和LSTM對比,我們保持相同的輸入維度、隱藏狀態維度,并使用相似的參數設置:

假設條件:

  • 輸入維度=3,隱藏狀態維度=4
  • 字符編碼:‘B’=[0.1,0,0], ‘o’=[0,0.1,0], ‘b’=[0,0,0.1]
  • GRU參數(簡化后):
    W_z = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    W_r = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    W_h = [[1,0,0,1,0,0,0], [0,1,0,0,1,0,0], [0,0,1,0,0,1,0], [0,0,0,1,0,0,1]]
    
    (注:每個權重矩陣實際為4x7,因拼接 h t ? 1 h_{t-1} ht?1?(4維)和 x t x_t xt?(3維))

詳細計算過程:

時間步1:輸入 ‘B’ = [0.1, 0, 0]

  1. 更新門計算:
    z 1 = σ ( W z ? [ h 0 , ′ B ′ ] + b z ) z_1 = \sigma(W_z \cdot [h_0, 'B'] + b_z) z1?=σ(Wz??[h0?,B]+bz?)
    假設 b z = [ 0 , 0 , 0 , 0 ] b_z=[0,0,0,0] bz?=[0,0,0,0],則:
    W z ? [ h 0 , ′ B ′ ] = [ [ 1 , 0 , 0 , 1 , 0 , 0 , 0 ] , . . . ] ? [ 0 , 0 , 0 , 0 , 0.1 , 0 , 0 ] T = [ 0.1 , 0 , 0 , 0 ] W_z \cdot [h_0, 'B'] = [[1,0,0,1,0,0,0], ...] \cdot [0,0,0,0,0.1,0,0]^T = [0.1, 0, 0, 0] Wz??[h0?,B]=[[1,0,0,1,0,0,0],...]?[0,0,0,0,0.1,0,0]T=[0.1,0,0,0]
    z 1 = σ ( [ 0.1 , 0 , 0 , 0 ] ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] z_1 = \sigma([0.1, 0, 0, 0]) = [0.525, 0.5, 0.5, 0.5] z1?=σ([0.1,0,0,0])=[0.525,0.5,0.5,0.5]

  2. 重置門計算:
    r 1 = σ ( W r ? [ h 0 , ′ B ′ ] + b r ) = [ 0.525 , 0.5 , 0.5 , 0.5 ] r_1 = \sigma(W_r \cdot [h_0, 'B'] + b_r) = [0.525, 0.5, 0.5, 0.5] r1?=σ(Wr??[h0?,B]+br?)=[0.525,0.5,0.5,0.5]

  3. 候選隱藏狀態:
    h ~ 1 = tanh ? ( W h ? [ r 1 ⊙ h 0 , ′ B ′ ] + b h ) \tilde{h}_1 = \tanh(W_h \cdot [r_1 \odot h_0, 'B'] + b_h) h~1?=tanh(Wh??[r1?h0?,B]+bh?)
    = tanh ? ( [ 0.1 , 0 , 0 , 0 ] ) = [ 0.099 , 0 , 0 , 0 ] = \tanh([0.1, 0, 0, 0]) = [0.099, 0, 0, 0] =tanh([0.1,0,0,0])=[0.099,0,0,0]

  4. 最終隱藏狀態:
    h 1 = ( 1 ? z 1 ) ⊙ h 0 + z 1 ⊙ h ~ 1 h_1 = (1-z_1) \odot h_0 + z_1 \odot \tilde{h}_1 h1?=(1?z1?)h0?+z1?h~1?
    = [ 0.475 , 0.5 , 0.5 , 0.5 ] ⊙ [ 0 , 0 , 0 , 0 ] + [ 0.525 , 0.5 , 0.5 , 0.5 ] ⊙ [ 0.099 , 0 , 0 , 0 ] = [0.475, 0.5, 0.5, 0.5] \odot [0,0,0,0] + [0.525, 0.5, 0.5, 0.5] \odot [0.099, 0, 0, 0] =[0.475,0.5,0.5,0.5][0,0,0,0]+[0.525,0.5,0.5,0.5][0.099,0,0,0]
    = [ 0.052 , 0 , 0 , 0 ] = [0.052, 0, 0, 0] =[0.052,0,0,0]

時間步2:輸入 ‘o’ = [0, 0.1, 0]

  1. 更新門計算:
    W z ? [ h 1 , ′ o ′ ] = [ [ 1 , 0 , 0 , 1 , 0 , 0 , 0 ] , . . . ] ? [ 0.052 , 0 , 0 , 0 , 0 , 0.1 , 0 ] T = [ 0.052 , 0.1 , 0 , 0 ] W_z \cdot [h_1, 'o'] = [[1,0,0,1,0,0,0], ...] \cdot [0.052,0,0,0,0,0.1,0]^T = [0.052, 0.1, 0, 0] Wz??[h1?,o]=[[1,0,0,1,0,0,0],...]?[0.052,0,0,0,0,0.1,0]T=[0.052,0.1,0,0]
    z 2 = σ ( [ 0.052 , 0.1 , 0 , 0 ] ) = [ 0.513 , 0.525 , 0.5 , 0.5 ] z_2 = \sigma([0.052, 0.1, 0, 0]) = [0.513, 0.525, 0.5, 0.5] z2?=σ([0.052,0.1,0,0])=[0.513,0.525,0.5,0.5]

  2. 重置門計算:
    r 2 = σ ( [ 0.052 , 0.1 , 0 , 0 ] ) = [ 0.513 , 0.525 , 0.5 , 0.5 ] r_2 = \sigma([0.052, 0.1, 0, 0]) = [0.513, 0.525, 0.5, 0.5] r2?=σ([0.052,0.1,0,0])=[0.513,0.525,0.5,0.5]

  3. 候選隱藏狀態:
    h ~ 2 = tanh ? ( W h ? [ r 2 ⊙ h 1 , ′ o ′ ] + b h ) \tilde{h}_2 = \tanh(W_h \cdot [r_2 \odot h_1, 'o'] + b_h) h~2?=tanh(Wh??[r2?h1?,o]+bh?)
    = tanh ? ( [ 0.027 , 0.1 , 0 , 0 ] ) = [ 0.027 , 0.099 , 0 , 0 ] = \tanh([0.027, 0.1, 0, 0]) = [0.027, 0.099, 0, 0] =tanh([0.027,0.1,0,0])=[0.027,0.099,0,0]

  4. 最終隱藏狀態:
    h 2 = ( 1 ? z 2 ) ⊙ h 1 + z 2 ⊙ h ~ 2 h_2 = (1-z_2) \odot h_1 + z_2 \odot \tilde{h}_2 h2?=(1?z2?)h1?+z2?h~2?
    = [ 0.026 , 0 , 0 , 0 ] + [ 0.014 , 0.05 , 0 , 0 ] = [ 0.04 , 0.05 , 0 , 0 ] = [0.026, 0, 0, 0] + [0.014, 0.05, 0, 0] = [0.04, 0.05, 0, 0] =[0.026,0,0,0]+[0.014,0.05,0,0]=[0.04,0.05,0,0]

時間步3:輸入 ‘b’ = [0, 0, 0.1]

  1. 更新門計算:
    W z ? [ h 2 , ′ b ′ ] = [ 0.04 , 0.05 , 0.1 , 0 ] W_z \cdot [h_2, 'b'] = [0.04, 0.05, 0.1, 0] Wz??[h2?,b]=[0.04,0.05,0.1,0]
    z 3 = σ ( [ 0.04 , 0.05 , 0.1 , 0 ] ) = [ 0.51 , 0.512 , 0.525 , 0.5 ] z_3 = \sigma([0.04, 0.05, 0.1, 0]) = [0.51, 0.512, 0.525, 0.5] z3?=σ([0.04,0.05,0.1,0])=[0.51,0.512,0.525,0.5]

  2. 重置門計算:
    r 3 = σ ( [ 0.04 , 0.05 , 0.1 , 0 ] ) = [ 0.51 , 0.512 , 0.525 , 0.5 ] r_3 = \sigma([0.04, 0.05, 0.1, 0]) = [0.51, 0.512, 0.525, 0.5] r3?=σ([0.04,0.05,0.1,0])=[0.51,0.512,0.525,0.5]

  3. 候選隱藏狀態:
    h ~ 3 = tanh ? ( W h ? [ r 3 ⊙ h 2 , ′ b ′ ] + b h ) \tilde{h}_3 = \tanh(W_h \cdot [r_3 \odot h_2, 'b'] + b_h) h~3?=tanh(Wh??[r3?h2?,b]+bh?)
    = tanh ? ( [ 0.02 , 0.026 , 0.1 , 0 ] ) = [ 0.02 , 0.026 , 0.099 , 0 ] = \tanh([0.02, 0.026, 0.1, 0]) = [0.02, 0.026, 0.099, 0] =tanh([0.02,0.026,0.1,0])=[0.02,0.026,0.099,0]

  4. 最終隱藏狀態:
    h 3 = ( 1 ? z 3 ) ⊙ h 2 + z 3 ⊙ h ~ 3 h_3 = (1-z_3) \odot h_2 + z_3 \odot \tilde{h}_3 h3?=(1?z3?)h2?+z3?h~3?
    = [ 0.02 , 0.025 , 0 , 0 ] + [ 0.01 , 0.013 , 0.052 , 0 ] = [ 0.03 , 0.038 , 0.052 , 0 ] = [0.02, 0.025, 0, 0] + [0.01, 0.013, 0.052, 0] = [0.03, 0.038, 0.052, 0] =[0.02,0.025,0,0]+[0.01,0.013,0.052,0]=[0.03,0.038,0.052,0]

三種模型的最終特征表示對比

模型"Bob"的特征表示(最終隱藏狀態)
RNN[0, 0, 0.099, 0.292]
LSTM[0.015, 0.02, 0.027, 0]
GRU[0.03, 0.038, 0.052, 0]

關鍵差異分析:

  1. 信息融合方式

    • RNN直接累加輸入,導致后期信息主導
    • LSTM通過細胞狀態長期記憶,但計算復雜
    • GRU通過更新門動態平衡歷史與當前信息,計算效率更高
  2. 參數效率

    • GRU參數量約為LSTM的2/3,訓練速度更快
    • 在短序列任務中,GRU通常能達到與LSTM接近的性能

4.3 GRU在Pytorch中的API

  1. GRU類定義與核心參數
torch.nn.GRU(input_size,           # 輸入特征維度hidden_size,          # 隱藏狀態維度num_layers=1,         # 堆疊的GRU層數bias=True,            # 是否使用偏置batch_first=False,    # 輸入格式是否為(batch, seq, feature)dropout=0,            # Dropout概率bidirectional=False   # 是否為雙向GRU
)
  1. 輸入與輸出格式
    輸入參數:

    • input:輸入序列,形狀為(seq_len, batch, input_size)(默認)或(batch, seq_len, input_size)batch_first=True
    • h_0:初始隱藏狀態,形狀為(num_layers * num_directions, batch, hidden_size)

    輸出參數:

    • output:所有時間步的隱藏狀態,形狀為(seq_len, batch, hidden_size * num_directions)
    • h_n:最后一個時間步的隱藏狀態,形狀同h_0
  2. 關鍵屬性與方法
    權重矩陣:

    • weight_ih_l[k]:第k層的輸入到隱藏的權重(重置門和更新門合并)
    • weight_hh_l[k]:第k層的隱藏到隱藏的權重
    • bias_ih_l[k]bias_hh_l[k]:對應偏置

    前向傳播方法:

output, h_n = gru(input, h_0)  # 與LSTM相比,少了細胞狀態c_n

3.4 代碼示例

  1. 基本用法
import torch
import torch.nn as nn# 創建GRU模型
gru = nn.GRU(input_size=10,      # 輸入特征維度hidden_size=20,     # 隱藏狀態維度num_layers=2,       # 2層GRU堆疊batch_first=True,   # 使用(batch, seq, feature)格式bidirectional=True  # 雙向GRU
)# 準備輸入
batch_size = 3
seq_len = 5
x = torch.randn(batch_size, seq_len, 10)  # 輸入序列# 初始化隱藏狀態(可選)
h0 = torch.zeros(2*2, batch_size, 20)  # 2層 * 雙向# 前向傳播
output, hn = gru(x, h0)# 輸出形狀分析
print("Output shape:", output.shape)      # (3, 5, 40)  [batch, seq, hidden*2]
print("Final hidden shape:", hn.shape)    # (4, 3, 20)  [layers*directions, batch, hidden]
  1. 獲取最后時間步的隱藏狀態
# 方法1:從output中獲取
last_output = output[:, -1, :]  # (batch, hidden*directions)# 方法2:從hn中獲取
last_hidden = hn[-2:] if gru.bidirectional else hn[-1]  # 雙向時需拼接兩個方向
last_hidden = torch.cat([last_hidden[0], last_hidden[1]], dim=1) if gru.bidirectional else last_hidden

五、三大模型的對比與實踐選擇

5.1 核心指標對比

模型門控數量參數量(輸入n→隱藏m)長期依賴能力計算效率
傳統RNN0nm + mm
LSTM44*(nm + mm)
GRU23*(nm + mm)

5.2 適用場景建議

  • 傳統RNN
    短序列任務(如長度<20的文本分類)、計算資源嚴格受限場景

  • LSTM
    長序列建模(機器翻譯、語音識別)、對精度要求高的任務

  • GRU
    中等長度序列(如對話系統、時間序列預測)、希望平衡精度與效率的場景

5.3 要點

  1. 梯度處理
    • LSTM/GRU天然緩解梯度消失,但仍需配合梯度裁剪(gradient clipping)防止爆炸
  2. 參數初始化
    • 傳統RNN需謹慎初始化權重以避免梯度問題
  3. 雙向與多層
    • 雙向結構可捕捉雙向依賴,多層網絡提升特征提取能力,但會顯著增加計算量

循環神經網絡的進化史是模型表達能力與計算效率的平衡藝術。從RNN到LSTM再到GRU,每一次改進都圍繞"如何更高效地建模序列依賴"展開。在實際應用中,應根據數據長度、計算資源和任務精度要求,選擇最適合的模型架構。

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

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

相關文章

多云密鑰統一管理實戰:CKMS對接阿里云/華為云密鑰服務

某保險公司因阿里云KMS密鑰與華為云密鑰割裂管理&#xff0c;導致勒索事件中解密失敗&#xff01;據統計&#xff0c;73%企業因多云密鑰分散管理引發數據恢復延遲&#xff08;IDC 2024&#xff09;。本文將詳解安當CKMS統一納管方案&#xff0c;實現跨云密鑰全生命周期管控&…

光伏接入承載力計算仿真:基于圖計算技術的自動建模技術研究

光伏接入承載力計算仿真:基于圖計算技術的自動建模技術研究 一、 引言:挑戰與機遇 光伏發電的大規模接入對中低壓配電網的安全穩定運行帶來了巨大挑戰。精確評估電網對光伏的承載力(Hosting Capacity, HC)是保障消納與安全的關鍵。傳統承載力評估嚴重依賴電網仿真,而仿真…

如何在Excel中每隔幾行取一行

如何在Excel中每隔幾行取一行 摘要&#xff1a; Excel中快速實現每隔n行取一行的技巧&#xff1a;使用OFFSET函數配合ROW函數即可實現。公式為OFFSET(起始單元格,(ROW(A1)-1)*n,)&#xff0c;其中n為間隔行數。例如從A2開始每2行取一行&#xff0c;公式為OFFSET(A2,(ROW(A1)-1)…

【MariaDB】MariaDB Server 11.3.0 Alpha下載、安裝、配置

MariaDB是一個開源關系型數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;由MySQL的原始開發者Michael Widenius主導開發。作為MySQL的分支&#xff0c;MariaDB旨在保持與MySQL的高度兼容性&#xff0c;同時提供性能優化、新功能和更好的開源承諾。 目錄 MariaDB下載 …

如何保證緩存和數據庫的雙寫一致性

程序員面試資料大全&#xff5c;各種技術書籍等資料-1000G IDEA開發工具- FREE 一、雙寫一致性問題本質 在分布式系統中&#xff0c;緩存與數據庫雙寫一致性指當數據被修改時&#xff0c;如何確保緩存&#xff08;如Redis&#xff09;和數據庫&#xff08;如MySQL&#xff09…

Qt 5.9 XML文件寫入指南

Qt 5.9 XML文件寫入指南 在Qt 5.9中&#xff0c;有多種方法可以編寫XML文件。下面我將介紹三種主要方法&#xff0c;并提供完整的代碼示例和最佳實踐。 三種XML寫入方法對比 方法優點缺點適用場景QXmlStreamWriter高效、內存占用低無樹形結構大型XML文件QDomDocument樹形結構…

一些ubuntu命令記錄(持續補充)

一、查看代碼運行占用的內存 1、使用 top 命令 top 命令是一個實時的系統監控工具&#xff0c;可以顯示當前系統中所有進程的資源使用情況。運行以下命令&#xff1a; top 在 top 界面中&#xff0c;可以看到每個進程的內存使用情況&#xff08;%MEM 列&#xff09;。 如何…

今日學習:音視頻領域入門文章參考(待完善)

音視頻領域概覽 入門文章參考 CSDN 雷神 博客園 2022-5-22

.npmrc和.yarnrc配置文件介紹:分別用于 Node.js 中的 npm(Node Package Manager)和 Yarn 包管理工具

.npmrc 和 .yarnrc 是兩個配置文件&#xff0c;分別用于 Node.js 中的 npm&#xff08;Node Package Manager&#xff09;和 Yarn 包管理工具。它們存儲了與包管理相關的配置選項&#xff0c;允許用戶自定義和控制包的安裝、版本、緩存等行為。下面是它們的詳細說明&#xff1a…

數字人分身 + 矩陣系統聚合:源碼搭建,支持OEM

在 AIGC 技術爆發的當下&#xff0c;數字人分身已從概念走向實用&#xff0c;而矩陣系統的聚合能力則讓單個數字人分身突破場景限制&#xff0c;實現 “一人多崗” 的規模化應用。無論是企業客服、直播帶貨&#xff0c;還是教育培訓、虛擬社交&#xff0c;數字人分身 矩陣系統…

學習昇騰開發的第12天--安裝第三方依賴

第三方依賴安裝指導&#xff08;C樣例&#xff09; 前置條件 1. 按照官方指導文檔完成CANN包安裝。 2. CANN版本需要>5.0.4.alpha001&#xff0c;低于此版本請參見昇騰CANN樣例倉介紹中的版本說明切換tag并使用發行版。 安裝須知 samples倉中的部分c樣例使用到opencv&am…

機器人仿真(1)Ubuntu24.04下CLion的ROS2開發環境配置

目錄 一、前言二、配置要求安裝ROS2安裝CLion 三、配置步驟四、后記 一、前言 近日CLion已開放非商用免費使用。相比教程中常用的VSCode&#xff0c;CLion在自動補全、調試和環境變量配置等方面表現更為出色。不過截至本文撰寫時&#xff0c;CLion官網僅提供了Windows系統下的…

WPF兩種綁定方式的分析

一、兩種綁定方式的分析 你提供的代碼展示了兩種不同的屬性綁定實現方式&#xff1a;傳統的CLR屬性配合INotifyPropertyChanged接口&#xff0c;以及WPF依賴屬性(DependencyProperty)系統。 相同點 目的相同&#xff1a;兩種方式都是為了實現屬性值變化時通知UI更新數據綁定…

【零基礎學AI】第14講:支持向量機實戰 - 文本分類系統

本節課你將學到 理解支持向量機的核心思想和幾何直覺 掌握SVM的關鍵參數和核函數選擇 學會文本數據預處理和特征提取 完成一個郵件分類項目 對比SVM與其他算法的性能差異 開始之前 環境要求 Python 3.8內存: 建議2GB 需要安裝的包 pip install pandas numpy scikit-learn …

美團 mtgsig1.2 最新版分析

聲明: 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向分析 部分代碼 result cp.call…

【實戰】CRMEB Pro 企業版安裝教程(附 Nginx 反向代理配置 + 常見問題解決)

一、前言 CRMEB Pro 是一款企業級高并發高性能的電商系統&#xff0c;支持 Linux 服務器環境&#xff0c;需要 PHP 8.0 及以上版本&#xff0c;兼容多種 WEB 服務器&#xff08;如 Nginx 和 Apache&#xff09;&#xff0c;并支持 MySQL 數據庫。本文將詳細介紹如何從零開始安…

解決Linux下根目錄磁盤空間不足的問題

ubantu中提示根目錄磁盤空間不足 解決辦法&#xff1a;對根目錄磁盤空間進行擴展。 一、使用lsblk查看磁盤使用情況 命令行輸入&#xff1a;lsblk aaaubuntu:~/Desktop$ lsblk可以看到sda5是掛載在根目錄上的。所以我們要對sda5進行擴展 二、擴展硬盤空間 1、關閉虛擬機 2、…

【C++】--入門

前面我們學習C語言的時候&#xff0c;我們也有講過C的部分歷史&#xff0c;我們看其名字就知道其和我們的C語言肯定是有密不可分的關系的&#xff0c;我們的C是在C的基礎上發展的&#xff0c;其彌補了C語?在表達能?、可維護性 和可擴展性??的不?。 下面為C的近年來的幾次…

JAVA內存區域劃分

根據《JAVA虛擬機規范》的規定&#xff0c;JAVA虛擬機在執行JAVA程序的過程中會把內存劃分為不同的數據區域。不同類型的數據會存儲在不同的區域&#xff0c;理解JAVA內存區域的工作細節對理解JAVA多線程、線程安全性有著重要意義。 注意&#xff0c;JAVA內存區域的劃分與我們…

Navicat 導入 SQL 文件

1. 安裝并打開 Navicat 安裝 Navicat&#xff08;如 Navicat Premium、Navicat for MySQL&#xff09;&#xff0c;百度或者淘寶就有很多破解版。 打開 Navicat&#xff0c;進入主界面。 2. 新建數據庫連接 點擊左上角 “連接” 按鈕&#xff0c;選擇你對應的數據庫類型&…