PyTorch與自然語言處理:從零構建基于LSTM的詞性標注器

目錄

1.詞性標注任務簡介

2.PyTorch張量:基礎數據結構

2.1 張量創建方法

2.2 張量操作

3 基于LSTM的詞性標注器實現

4.模型架構解析

5.訓練過程詳解

6.SGD優化器詳解

6.1 SGD的優點

6.2 SGD的缺點

7.實用技巧

7.1 張量形狀管理

7.2 廣播機制

8.關鍵技術原理

8.1?詞性標注的挑戰與LSTM解決方案

8.2 數據表示與預處理

8.3 損失函數選擇

9、擴展與改進方向

10、總結


1.詞性標注任務簡介

詞性標注是自然語言處理的基礎任務,目標是為句子中的每個單詞分配一個詞性標簽(如名詞、動詞、限定詞等)。這項任務的挑戰在于單詞的詞性通常取決于上下文——例如,"read"在"They read that book"中是動詞,但在其他語境中可能有不同的詞性。

詞性標注對許多下游NLP任務至關重要,包括:

  • 句法分析
  • 命名實體識別
  • 問答系統
  • 機器翻譯

2.PyTorch張量:基礎數據結構

在深入模型架構之前,讓我們先了解PyTorch的核心數據結構:張量(Tensor)。類似于NumPy的ndarray,在PyTorch框架下,張量(Tensor)成為連接這一任務各個環節的核心數據結構。張量不僅提供了高效的數學運算能力,還支持GPU加速,使復雜的神經網絡計算變得可行。實質上,從輸入數據到模型參數,再到最終預測結果,整個詞性標注過程中的每一步都通過張量來表示和操作。

2.1 張量創建方法

PyTorch提供多種創建張量的方式:

# 從Python列表創建
x1 = torch.tensor([1, 2, 3])# 根據預定義形狀創建
x2 = torch.zeros(2, 3)  # 2×3全零張量
x3 = torch.eye(3)       # 3×3單位矩陣
x4 = torch.rand(2, 4)   # 從均勻分布采樣的隨機張量

2.2 張量操作

PyTorch支持兩種操作接口:

  • 函數式:torch.add(x, y)
  • 方法式:x.add(y)

此外,操作可以分為:

  • 原地操作:x.add_(y) (直接修改x,注意下劃線后綴)
  • 非原地操作:x.add(y) (返回新張量,不改變x)

3 基于LSTM的詞性標注器實現

現在,讓我們構建基于LSTM的詞性標注器。完整實現如下:

import torch
import torch.nn as nn
import torch.nn.functional as F# === 數據準備 ===
# 定義訓練數據:每個樣本為(句子單詞列表,詞性標簽列表)
# 詞性標簽說明:DET=限定詞, NN=名詞, V=動詞
training_data = [("The cat ate the fish".split(), ["DET", "NN", "V", "DET", "NN"]),("They read that book".split(), ["NN", "V", "DET", "NN"])
]# 定義測試數據:僅包含句子(無標簽,用于模型預測)
testing_data = [("They ate the fish".split())]# 構建單詞到索引的映射(詞匯表)
word_to_ix = {}
for sentence, tags in training_data:for word in sentence:if word not in word_to_ix:word_to_ix[word] = len(word_to_ix)
print("單詞索引映射:", word_to_ix)# 定義標簽到索引的映射(標簽集)
tag_to_ix = {"DET": 0, "NN": 1, "V": 2}# === 模型定義 ===
class LSTMTagger(nn.Module):def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size):super(LSTMTagger, self).__init__()self.hidden_dim = hidden_dim# 詞嵌入層(輸入層):將單詞索引轉換為向量self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)# LSTM層:處理序列數據,捕獲上下文信息self.lstm = nn.LSTM(embedding_dim, hidden_dim)# 線性層:將LSTM輸出映射到標簽空間(輸出層)self.hidden2tag = nn.Linear(hidden_dim, tagset_size)# 初始化隱藏狀態self.hidden = self.init_hidden()def init_hidden(self):"""初始化LSTM的隱藏狀態和細胞狀態(全零張量)"""return (torch.zeros(1, 1, self.hidden_dim),  # 隱藏狀態torch.zeros(1, 1, self.hidden_dim))  # 細胞狀態def forward(self, sentence):"""前向傳播函數"""# 1. 詞嵌入:將單詞索引轉換為向量embeds = self.word_embeddings(sentence)# 2. LSTM處理:輸入形狀需為(序列長度, 批量大小, 特征維度)lstm_out, self.hidden = self.lstm(embeds.view(len(sentence), 1, -1), self.hidden)# 3. 線性變換:將LSTM輸出映射到標簽分數tag_space = self.hidden2tag(lstm_out.view(len(sentence), -1))# 4. 計算標簽概率分布(對數softmax,便于NLLLoss計算)tag_scores = F.log_softmax(tag_space, dim=1)return tag_scores# === 模型初始化與配置 ===
# 超參數設置
EMBEDDING_DIM = 6    # 詞嵌入向量維度
HIDDEN_DIM = 6       # LSTM隱藏層維度# 實例化模型
model = LSTMTagger(EMBEDDING_DIM, HIDDEN_DIM, len(word_to_ix), len(tag_to_ix))# 定義損失函數和優化器
loss_function = nn.NLLLoss()  # 負對數似然損失(適用于多分類)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)  # 隨機梯度下降優化器# === 數據預處理函數 ===
def prepare_sequence(seq, to_ix):"""將單詞/標簽列表轉換為模型輸入的張量(索引序列)"""idxs = [to_ix[w] for w in seq]return torch.tensor(idxs, dtype=torch.long)# === 模型訓練 ===
for epoch in range(400):  # 訓練400輪for sentence, tags in training_data:# 梯度清零model.zero_grad()# 重置LSTM隱藏狀態model.hidden = model.init_hidden()# 數據預處理:轉換為索引張量sentence_tensor = prepare_sequence(sentence, word_to_ix)tags_tensor = prepare_sequence(tags, tag_to_ix)# 前向傳播:獲取標簽分數tag_scores = model(sentence_tensor)# 計算損失:比較預測分數與真實標簽loss = loss_function(tag_scores, tags_tensor)# 反向傳播:計算梯度loss.backward()# 參數更新:優化器調整模型參數optimizer.step()# 每50輪打印一次訓練進度if epoch % 50 == 0:print(f"Epoch {epoch}, Loss: {loss.item():.4f}")# === 模型預測 ===
def predict_tags(sentence):"""預測輸入句子的詞性標簽"""# 數據預處理sentence_tensor = prepare_sequence(sentence, word_to_ix)# 前向傳播with torch.no_grad():  # 預測時關閉梯度計算tag_scores = model(sentence_tensor)# 獲取每個位置分數最高的標簽索引_, predicted_indices = torch.max(tag_scores, 1)# 將索引映射回標簽名稱predicted_tags = [list(tag_to_ix.keys())[idx] for idx in predicted_indices]return predicted_tags# 對測試數據進行預測
print("\n=== 測試數據預測 ===")
for test_sentence in testing_data:print("輸入句子:", test_sentence)predicted = predict_tags(test_sentence)print("預測標簽:", predicted)# 檢查模型在訓練數據上的表現
print("\n=== 訓練數據預測 ===")
for (train_sentence, true_tags) in training_data:print("輸入句子:", train_sentence)print("真實標簽:", true_tags)predicted = predict_tags(train_sentence)print("預測標簽:", predicted)print("-" * 30)

4.模型架構解析

我們的詞性標注器采用三層神經網絡結構:

  1. 詞嵌入層:將離散的單詞索引轉換為密集向量表示,捕獲單詞之間的語義關系。每個單詞表示為6維向量。
  2. LSTM層:處理詞嵌入序列,維護隱藏狀態以捕獲上下文信息。這解決了詞性依賴于周圍單詞的挑戰。
  3. 線性層:將LSTM在各位置的隱藏狀態映射到標簽分數,然后通過對數softmax轉換為概率分布。

5.訓練過程詳解

模型訓練涉及幾個關鍵步驟:

  1. 梯度清零model.zero_grad()清除之前的梯度,防止累加。
  2. 隱藏狀態重置model.hidden = model.init_hidden()在處理每個句子前重置LSTM隱藏狀態。
  3. 前向傳播:模型處理句子,輸出標簽分數。
  4. 損失計算:負對數似然損失比較預測標簽分數與真實標簽。
  5. 反向傳播loss.backward()計算梯度。
  6. 參數更新:SGD優化器根據梯度調整模型參數。

6.SGD優化器詳解

隨機梯度下降(SGD)優化器用于更新模型參數以最小化損失函數:

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

SGD更新公式為: θ(t+1) = θ(t) - η · ?L(θ(t))

其中:

  • θ表示模型參數
  • η(學習率)控制步長
  • ?L(θ)是損失函數的梯度

6.1 SGD的優點

  • 實現簡單高效
  • 內存友好(無需存儲梯度歷史)
  • 對簡單模型且訓練充分時效果良好

6.2 SGD的缺點

  • 梯度方差大(更新噪聲大)
  • 可能在局部最小值附近震蕩
  • 需要手動調整學習率
  • 不能自適應地調整學習步長

7.實用技巧

7.1 張量形狀管理

PyTorch提供多種函數管理張量維度:

  • view:重塑張量形狀(類似NumPy的reshape)
  • unsqueeze:添加一個大小為1的維度
  • squeeze:移除大小為1的維度

在模型中,我們使用view確保張量形狀符合LSTM要求:

embeds.view(len(sentence), 1, -1)  # 重塑為[序列長度, 批量大小, 嵌入維度]

7.2 廣播機制

PyTorch的廣播機制允許不同形狀的張量進行算術運算。這在數據歸一化時特別有用:

# 按批次維度求均值(keepdim=True保留維度結構)
batch_mean = tensor.mean(dim=0, keepdim=True)  # 形狀: [1, 特征數]
normalized = tensor - batch_mean  # 廣播允許此操作

關于dimkeepdim參數的使用:

  • dim參數:指定歸并的維度(如dim=0按列歸并,dim=1按行歸并),歸并后該維度被壓縮。
  • keepdim參數:當設為True時,保持歸并后的維度為1,便于后續廣播操作,避免維度不匹配錯誤。

例如,對于形狀為(2,3)的張量a:

  • a.sum(dim=0)結果形狀為(3,),維度數減少
  • a.sum(dim=0, keepdim=True)結果形狀為(1,3),維度數保持不變

8.關鍵技術原理

8.1?詞性標注的挑戰與LSTM解決方案

詞性標注的主要挑戰是單詞的詞性依賴于上下文。LSTM網絡通過其特殊的門控機制有效解決了這一問題:

  • 輸入門:控制當前輸入的影響程度
  • 遺忘門:控制歷史信息的保留程度
  • 輸出門:控制內部狀態的輸出程度

這種設計使LSTM能夠長期保留重要信息,過濾無關信息,從而有效地捕獲句子中的上下文依賴關系。

8.2 數據表示與預處理

  1. 單詞索引化:將單詞轉換為唯一整數索引,構建詞匯表。
  2. 標簽索引化:將詞性標簽映射到整數索引。
  3. 批處理:雖然示例使用單句訓練,但實際應用中通常會使用小批量提高效率。

8.3 損失函數選擇

我們使用負對數似然損失(NLLLoss)結合對數softmax輸出,這是多分類問題的標準組合:

  • log_softmax將模型輸出轉換為對數概率分布
  • NLLLoss計算預測標簽的負對數概率,鼓勵模型提高正確標簽的預測概率

9、擴展與改進方向

為了增強模型性能,可以考慮:

  1. 使用預訓練詞嵌入(如Word2Vec或GloVe)
  2. 實現雙向LSTM以捕獲雙向上下文
  3. 添加條件隨機場(CRF)層實現序列級預測
  4. 使用更大的真實數據集如Penn Treebank語料庫
  5. 嘗試注意力機制提升長距離依賴的建模能力
  6. 引入字符級特征處理未登錄詞問題

10、總結

通過構建這個基于LSTM的詞性標注器,我們展示了PyTorch在NLP任務中的強大能力。盡管模型結構相對簡單(僅使用6維嵌入和隱藏狀態),但通過捕獲上下文信息,它能有效學習標注單詞的詞性。

這個項目涵蓋了PyTorch的多個核心概念:

  • 張量創建與操作
  • 使用nn.Module構建神經網絡
  • 管理LSTM隱藏狀態
  • 通過反向傳播訓練
  • 利用優化器更新參數

隨著深度學習和NLP領域的發展,這些基礎知識將為更復雜的模型架構(如基于Transformer的架構)奠定基礎,這些高級模型憑借捕獲文本中長距離依賴的能力,已經徹底革新了自然語言處理領域。

希望這篇博客能幫助您深入理解PyTorch在NLP中的應用,并為您的項目提供有價值的指導!

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

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

相關文章

【C++】特殊類的設計、單例模式以及Cpp類型轉換

📚 博主的專欄 🐧 Linux | 🖥? C | 📊 數據結構 | 💡C 算法 | 🌐 C 語言 上篇文章: C 智能指針使用,以及shared_ptr編寫 下篇文章: C IO流 目錄 特殊類的設…

探索 Flowable 后端表達式:簡化流程自動化

什么是后端表達式? 在 Flowable 中,后端表達式是一種強大的工具,用于在流程、案例或決策表執行期間動態獲取或設置變量。它還能實現自定義邏輯,或將復雜邏輯委托…… 后端表達式在 Flowable 的后端運行,無法訪問前端…

【Lua】Lua 入門知識點總結

Lua 入門學習筆記 本教程旨在幫助有編程基礎的學習者快速入門Lua編程語言。包括Lua中變量的聲明與使用,包括全局變量和局部變量的區別,以及nil類型的概念、數值型、字符串和函數的基本操作,包括16進制表示、科學計數法、字符串連接、函數聲明…

符號速率估計——小波變換法

[TOC]符號速率估計——小波變換法 一、原理 1.Haar小波變換 小波變換在信號處理領域被成為數學顯微鏡,不同于傅里葉變換,小波變換可以觀測信號隨時間變換的頻譜特征,因此,常用于時頻分析。 ??當小波變換前后位置處于同一個碼元…

android contentProvider 踩坑日記

寫此筆記原因 學習《第一行代碼》到第8章節實現provider時踩了一些坑,因此記錄下來給后來人和自己一個提示,僅此而已。 包含內容 Sqlite數據庫CURD內容provider界面provider項目中書籍管理provider實現邏輯用adb shell確認providercontentResolver接收…

Eureka、LoadBalance和Nacos

Eureka、LoadBalance和Nacos 一.Eureka引入1.注冊中心2.CAP理論3.常見的注冊中心 二.Eureka介紹1.搭建Eureka Server 注冊中心2.搭建服務注冊3.服務發現 三.負載均衡LoadBalance1.問題引入2.服務端負載均衡3.客戶端負載均衡4.Spring Cloud LoadBalancer1).快速上手2)負載均衡策…

【開關電源】關于GaN反激電源開關噪聲

文章目錄 0 前言1 設計信息1.1 設計需求1.2 原理圖1.3 電源表現 2 原因分析3 橫向對比TI UCG28826 (GaN)采購的普通QR反激變換器 4 總結 0 前言 筆者原計劃設計一款省電的,效率尚可的,穩定的2路輸出反激電源,用于系統…

DOCA介紹

本文分為兩個部分: DOCA及BlueField介紹如何運行DOCA應用,這里以DNS_Filter為例子做大致介紹。 DOCA及BlueField介紹: 現代企業數據中心是軟件定義的、完全可編程的基礎設施,旨在服務于跨云、核心和邊緣環境的高度分布式應用工作…

mybatis mapper.xml中使用枚舉

重點:application.propertis配置類 #TypeEnumHandler 這個類的包名,不是全路徑 mybatis.type-handlers-packagecom.fan.test.handler兩個枚舉類: public enum StatusEnum {DELETED(0),ACTIVE(1);private final int code;StatusEnum(int cod…

鴻蒙生態:鴻蒙生態校園行心得

(個人觀點,僅供參考) 兄弟們,今天來淺淺聊一聊這次的設立在長沙的鴻蒙生態行活動。 老樣子,我們先來了解一下這個活動: Harmon&#x…

【速寫】多LoRA并行衍生的一些思考

遷移學習上的一個老問題,怎么做多領域的遷移?以前的邏輯認為領域遷移屬于是對參數做方向性的調整,如果兩個領域方向相左,實際上不管怎么加權相加都是不合理的。 目前一些做法想著去觀察LoRA權重矩陣中的稠密塊與稀疏塊&#xff0…

【Delphi 基礎知識 44】接口interface的應用

目錄 1. 前言2. 接口有哪些優勢2.1. 實現多態性2.2 實現多重(解決單繼承限制)2.3 解耦代碼(依賴注入)2.4 便于測試(模擬接口)2.5 跨語言互操作性(COM支持)1. 前言 總結為一句話就是:接口只告訴你要做什么,而類會告訴你應該怎么做 下面是最簡單的接口實現 typeIMyIn…

09.傳輸層協議 ——— TCP協議

文章目錄 TCP協議 談談可靠性TCP協議格式 序號與確認序號窗口大小六個標志位 確認應答機制(ACK)超時重傳機制連接管理機制 三次握手四次揮手 流量控制滑動窗口擁塞控制延遲應答捎帶應答面向字節流粘包問題TCP異常情況TCP小結基于TCP的應用層協議 TCP協…

NLP高頻面試題(五十一)——LSTM詳解

長短期記憶網絡(LSTM)相較于傳統循環神經網絡(RNN)的核心改進在于通過引入記憶單元(cell state)和門機制(gating mechanism)來有效緩解梯度消失與梯度爆炸問題,從而更好地捕捉長距離依賴關系 。在其網絡結構中,信息通過輸入門(input gate)、遺忘門(forget gate)和…

SpringCloud組件—Eureka

一.背景 1.問題提出 我們在一個父項目下寫了兩個子項目,需要兩個子項目之間相互調用。我們可以發送HTTP請求來獲取我們想要的資源,具體實現的方法有很多,可以用HttpURLConnection、HttpClient、Okhttp、 RestTemplate等。 舉個例子&#x…

無需花錢購買域名服務器!使用 VuePress + Github 30分鐘搭建屬于自己的博客網站(保姆級教程)

前言 GitHub Pages 提供免費全球加速的服務器資源,VuePress 將 Markdown 變成藝術品級的網頁,僅需 30 分鐘,你便可以像提交代碼一樣發布文章,過程完全免費。 博客搭建好的效果如下:https://honorsong.github.io/exam…

提交到Gitee倉庫

文章目錄 注冊配置公鑰創建空白的碼云倉庫把本地項目上傳到碼云對應的空白倉庫中 注冊 注冊并激活碼云賬號( 注冊頁面地址:https://gitee.com/signup ) 可以在自己C盤/用戶/用戶名/.ssh 可以看到 有id_rsa.pub 以前在GitHub注冊時搞過&…

如何在 Java 中從 PDF 文件中刪除頁面(教程)

由于 PDF 文件格式不是 Java 原生支持的,因此要從 PDF 中刪除頁面,你需要使用外部庫。 本教程介紹如何使用 JPedal 來實現這一功能。 開始使用 ? 將 JPedal 添加到你的類路徑或模塊路徑中(可從官網下載安裝試用版 JAR 文件) ?…

機器學習第二篇 多變量線性回歸

數據集:世界幸福指數數據集中的變量有幸福指數排名、國家/地區、幸福指數得分、人均國內生產總值、健康預期壽命、自由權、社會支持、慷慨程度、清廉指數。我們選擇GDP per Capita和Freedom,來預測幸福指數得分。 文件一:linear,…

位運算,狀態壓縮dp(算法競賽進階指南學習筆記)

目錄 移位運算一些位運算的操作最短 Hamilton 路徑(狀態壓縮dp模板,位運算) 0x是十六進制常數的開頭;本身是聲明進制,后面是對應具體的數; 數組初始化最大值時用0x3f賦值; 移位運算 左移 把二…