《零基礎入門AI:深度學習之NLP基礎學習》

一、自然語言處理(NLP)概述

1. 基本概念

? 自然語言處理(Natural Language Processing, NLP)是人工智能與計算語言學交叉的核心領域,致力于實現計算機對人類自然語言的自動理解、分析、生成與交互。其研究目標在于構建能夠處理文本或語音輸入,并執行語義解析、信息提取、語言生成等任務的計算系統。

NLP 的技術基礎涵蓋多個學科,包括:

  • 計算機科學:提供算法設計、數據結構與系統實現支持;
  • 人工智能:引入機器學習與深度學習方法,實現語言建模與推理;
  • 語言學:為語法結構、語義表示與語用分析提供理論依據;
  • 統計學與數學:支撐概率模型、向量空間表示與優化方法。

在中文語言環境下,NLP 面臨若干特有的技術挑戰,主要源于中文的語言特性:

  • 分詞必要性:中文書寫不以空格分隔詞語,需依賴分詞算法(Word Segmentation)將連續字符序列切分為有意義的詞匯單元,例如將“北京冬奧會”切分為 ["北京", "冬奧", "會"]
  • 歧義問題:存在多種切分可能性,如“南京市長江大橋”可解析為“南京市/長江大橋”或“南京/市長/江大橋”,需結合上下文進行消歧。
  • 形態貧乏:中文缺乏如英文的屈折變化(如時態、單復數),語法信息主要依賴語序與虛詞表達。
  • 語義依賴上下文:省略、指代和語境依賴現象普遍,增加了語義解析的復雜性。

因此,中文 NLP 系統通常需要集成專用的分詞工具(如 Jieba、THULAC、LTP)以及針對中文語料訓練的語言模型(如 BERT-wwm、ERNIE、Chinese-BERT-wwm)。

2. 主要任務與功能

NLP 的研究與應用可劃分為兩大類:語言理解(Natural Language Understanding, NLU)與語言生成(Natural Language Generation, NLG)。

2.1 語言理解任務

語言理解旨在從輸入文本中提取結構化信息或語義表示,典型任務包括:

  • 文本分類(Text Classification):將文本映射到預定義類別,如新聞分類(體育、財經、科技)、垃圾郵件檢測等。
  • 情感分析(Sentiment Analysis):識別文本中表達的情感傾向,通常分為正面、負面與中性,廣泛應用于輿情監控與用戶反饋分析。
  • 命名實體識別(Named Entity Recognition, NER):識別文本中具有特定意義的實體,如人名、地名、組織機構、時間等,并進行分類。
  • 語義角色標注(Semantic Role Labeling, SRL):分析句子中謂詞與其論元之間的語義關系,例如識別“施事”、“受事”、“時間”、“地點”等角色。
  • 問答系統(Question Answering, QA):根據自然語言問題,在給定文本中定位或生成答案,可分為抽取式問答與生成式問答。
  • 句法分析(Syntactic Parsing):構建句子的語法結構樹,包括依存句法分析與成分句法分析。
2.2 語言生成任務

語言生成關注如何根據語義表示或結構化數據生成符合語法與語用規范的自然語言文本,主要任務包括:

  • 機器翻譯(Machine Translation, MT):將源語言文本自動轉換為目標語言,如中英互譯。
  • 文本摘要(Text Summarization):生成原文的簡潔摘要,分為抽取式(選取原文句子)與生成式(重寫表達)。
  • 對話系統(Dialogue Systems):實現人機對話,包括任務型對話(如訂票)與開放域對話(如聊天機器人)。
  • 文本續寫與創作:基于上下文生成連貫的后續文本,應用于故事生成、代碼補全等場景。
2.3 語音與文本轉換

NLP 也常與語音技術結合,形成完整的語音交互系統:

  • 自動語音識別(Automatic Speech Recognition, ASR):將語音信號轉換為文本。
  • 語音合成(Text-to-Speech, TTS):將文本轉換為自然語音輸出。

3. 技術實現路徑與應用實踐

3.1 應用場景

NLP 技術已廣泛應用于多個領域,包括但不限于:

  • 信息檢索與搜索引擎:通過語義理解提升查詢與文檔的匹配精度。
  • 智能客服與虛擬助手:實現自動化問答與任務執行。
  • 社交媒體分析:進行情感分析、話題檢測與用戶畫像構建。
  • 金融與法律文本處理:用于合同解析、風險預警與合規審查。
  • 醫療自然語言處理:從電子病歷中提取臨床信息,輔助診斷決策。
3.2 技術實現流程

構建一個典型的 NLP 系統通常包括以下步驟:

  1. 數據預處理

    • 文本清洗:去除噪聲、標準化編碼。
    • 分詞與詞性標注:對中文文本進行分詞處理,并標注詞匯的語法屬性。
    • 去除停用詞:過濾常見但無實際語義貢獻的詞匯(如“的”、“了”)。
  2. 特征表示

    • 傳統方法:使用 One-Hot 編碼、TF-IDF 或 n-grams 表示文本。
    • 現代方法:采用詞向量(Word Embedding)技術,如 Word2Vec、GloVe 或上下文相關表示(如 BERT)。
  3. 模型構建

    • 傳統模型:樸素貝葉斯、支持向量機(SVM)、條件隨機場(CRF)。
    • 深度學習模型:循環神經網絡(RNN)、長短期記憶網絡(LSTM)、Transformer 架構及其變體(如 BERT、T5)。
  4. 訓練與評估

    • 在標注數據集上進行監督訓練。
    • 使用準確率、精確率、召回率、F1 分數、BLEU、ROUGE 等指標評估模型性能。
  5. 部署與應用

    • 將訓練好的模型集成至實際系統中,支持實時推理。
    • 可通過 API 接口、微服務或嵌入式方式部署。
3.3 開發工具與資源
  • 編程語言:Python 為當前主流開發語言,具備豐富的 NLP 庫支持。
  • 常用工具庫
    • 中文分詞:Jieba、THULAC、LTP、HanLP。
    • 英文處理:NLTK、spaCy。
    • 深度學習框架:PyTorch、TensorFlow。
  • 預訓練模型平臺
    • Hugging Face Transformers:提供大量開源預訓練模型(如 BERT、RoBERTa、T5)。
    • 百度 PaddleNLP、阿里云 NLP API:支持中文場景的模型與服務。

二、NLP中的特征工程

想象一下,計算機像一個“外星人”,它天生只懂數字(0 和 1),完全不懂人類的語言。當我們把“北京”、“運動員”、“比賽”這些文字扔給它時,它一臉懵:“這是什么鬼符號?”

為了讓計算機能“理解”語言,我們必須把文字轉換成它能處理的數學形式——也就是向量(Vector)

1. 傳統方法

1.1 One-Hot 編碼(不好用)

最簡單粗暴的方法是 One-Hot 編碼

  • 假設詞表有 10000 個詞。
  • “北京” → [1, 0, 0, ..., 0] (第1位是1,其余是0)
  • “運動員” → [0, 1, 0, ..., 0] (第2位是1,其余是0)
  • “比賽” → [0, 0, 1, ..., 0] (第3位是1,其余是0)

問題

  1. 維度爆炸:詞表越大,向量越長(10000維),非常稀疏(幾乎全是0),浪費內存。
  2. 沒有語義:向量之間完全獨立。北京運動員 的向量點積是 0,說明它們“毫不相關”。但人類知道,它們都和“冬奧會”有關!計算機學不到這種語義相似性
1.2 TF-IDF(引入權重)

TF-IDF 通過兩個指標為詞賦予權重:

  • 詞頻(TF):將文本中的每個單詞視為一個特征,并將文本中每個單詞的出現次數除以該單詞在所有文檔中的出現次數,即詞在文檔中出現的頻率。
  • 逆文檔頻率(IDF): 逆文檔頻率用來衡量一個詞在整個文檔集合(語料庫)中的重要性。它的目的是降低那些在很多文檔中頻繁出現的詞的權重,例如“the”、“is”這種常見詞,或者低頻罕見詞tetrafluoroethylene(四氟乙烯)。即詞在整個語料庫中出現越少,權重越高。

例如,“冬奧會”在體育新聞中 TF 高,IDF 也高(不是通用詞),因此 TF-IDF 值高,被認為是關鍵詞。

優點:能突出關鍵詞。
缺點:仍是高維稀疏表示,無法捕捉語義相似性。

結論:

  • 文檔頻率和樣本語義貢獻程度呈反相關
  • 文檔頻率和逆文檔頻率呈反相關
  • 逆文檔頻率和樣本語義貢獻度呈正相關
1.3 n-grams(捕捉局部上下文)

n-grams 是特征工程中的一種技術,它通過將文本中的連續 n 個詞(或字符)組合起來,形成一個短語來捕捉文本中的局部上下文信息。n 可以為 1、2、3 等,具體取決于希望捕捉的上下文范圍。

什么是 n-grams?

  • 1-gram(Unigram):每個單獨的詞作為一個單位。例如,“I love NLP” 的 1-gram 是 ["I", "love", "NLP"]
  • 2-grams(Bigram):相鄰的兩個詞組合成一個短語。例如,“I love NLP” 的 2-grams 是 ["I love", "love NLP"]
  • 3-grams(Trigram):相鄰的三個詞組合成一個短語。例如,“I love NLP” 的 3-grams 是 ["I love NLP"]

n-grams 的作用

使用 n-grams 可以捕捉詞之間的局部上下文關系。例如,1-gram 只關心詞的獨立出現頻率,而 bigram 和 trigram 能捕捉到詞之間的順序關系。例如,bigram "love NLP" 表示詞 “love” 和 “NLP” 是一起出現的,這種信息在建模中會比僅僅知道 “love” 和 “NLP” 出現頻率更有價值。

n-grams 的示例

假設句子為 “I love NLP and machine learning”:

  • 1-gram(Unigram): ["I", "love", "NLP", "and", "machine", "learning"]
  • 2-grams(Bigram): ["I love", "love NLP", "NLP and", "and machine", "machine learning"]
  • 3-grams(Trigram): ["I love NLP", "love NLP and", "NLP and machine", "and machine learning"]

通過這些 n-grams,模型可以捕捉到詞與詞之間的局部依賴關系。

? 將 n-gramsTF-IDF 相結合是文本特征工程中非常常見的做法,它不僅能夠捕捉詞與詞之間的局部關系,還能通過 TF-IDF 來衡量這些短語在整個語料庫中的重要性。結合的過程基本上是先生成 n-grams,然后對這些 n-grams 計算 TF-IDF 權重。

結合 n-grams 與 TF-IDF 的步驟:

  1. 生成 n-grams:首先從文本中生成 n-grams(n 可以是 1, 2, 3 等)。這些 n-grams 就像是詞的組合,通常使用 CountVectorizer 或類似的工具生成。
  2. 計算詞頻 (TF):統計每個 n-gram 在文本中出現的頻率。
  3. 計算逆文檔頻率 (IDF):計算 n-gram 在所有文檔中出現的頻率,稀有的 n-grams 會得到較高的權重,而常見的 n-grams 權重較低。
  4. 計算 TF-IDF:將每個 n-gram 的 TF 和 IDF 相乘,得到 TF-IDF 權重,表示該 n-gram 對特定文本的重要性。

注意:當使用 2-grams 時,I lovelove NLP 被看作是兩個單獨的特征,總共有兩個特征(總特征數 = 2)。

2. 現代方法:詞向量(Word Embedding)

2.1 什么是詞向量?

詞向量就是為每個詞分配一個短得多的、稠密的、實數向量,比如 50 維、100 維、300 維。

例如:

  • “北京” → [0.2, -0.8, 1.5, 0.1, -0.3] (5維)
  • “運動員” → [0.4, -0.7, 1.3, 0.2, -0.2] (5維)
  • “比賽” → [0.3, -0.75, 1.4, 0.15, -0.25] (5維)

理解

  • 這些數字不是隨便給的,而是通過大量文本訓練出來的。
  • 語義相近的詞,它們的向量也相近
    • “北京” 和 “上海” 的向量距離很近。
    • “國王” - “男人” + “女人” ≈ “王后” (著名的詞向量類比)
  • 計算機可以通過計算向量之間的距離相似度(如余弦相似度)來判斷詞語之間的關系。

一句話總結詞向量
詞向量是將一個詞表示成一個低維、稠密的實數向量,使得語義或語法上相似的詞在向量空間中的位置也相近。

2.2 關于“維度”的三大問題

”維度“指的是什么?

這里的“維度”(Dimension)指的就是向量的長度,也就是這個向量由多少個數字組成。

  • 1維:就是一個數字,比如 [3.14]
  • 2維:就是平面上的一個點,比如 [1.0, 2.5] (有 x 和 y 兩個坐標)
  • 3維:就是空間中的一個點,比如 [1.0, 2.5, 3.7] (有 x, y, z 三個坐標)
  • 5維:就是 [0.2, -0.8, 1.5, 0.1, -0.3] —— 它有 5 個數字。
  • 100維:就是有 100 個數字排成一列。

關鍵:我們人類只能直觀理解 2D 或 3D 空間。5維、100維、300維的空間是抽象的數學空間,我們無法在大腦中“畫”出來,但數學上完全可以定義和計算。

總結:維度 = 向量的長度 = 表示一個詞用了多少個數字。


每個維度代表的是什么?(最核心的問題)

很多人會想:“第1維是不是代表‘地理位置’?第2維是不是代表‘情感傾向’?第3維是不是代表‘人/物’?這些具體的特征指標。”

答案是:NO,詞向量的每個維度沒有明確、可解釋的物理或語義含義

正確的理解

  1. 整體才有意義:詞向量的整個向量(所有維度組合在一起)才代表這個詞的語義。就像你不能說“紅色”是由“波長”和“亮度”兩個獨立的“維度”組成,而是整個光譜特性定義了“紅色”。

  2. 分布式表示 (Distributed Representation)

    • 一個詞的語義信息是分布在整個向量的所有維度上的。
    • 每個維度都可能對多個不同的語義特征都有微弱的貢獻。
    • 沒有哪個維度是專門負責“國家”或“動詞”的。
  3. 語義是幾何關系

    • 詞向量的威力不在于單個數字,而在于向量之間的幾何關系
      • 距離近:語義相似(如 “北京” 和 “上海” 的向量距離近)。
      • 方向一致:語義類比(如 “國王” - “男人” + “女人” ≈ “王后”)。
    • 計算機通過學習這些整體的模式和關系來理解語言。

一個類比

想象一下“顏色”。

  • 我們用 RGB 三元組來表示顏色,比如 (255, 0, 0) 是紅色,(0, 255, 0) 是綠色。
  • 你能說 R 分量(紅色)就代表“暖色調”嗎?不能!因為 (255, 255, 0)(黃色)也是暖色,但 G 分量也很高。
  • 顏色的“含義”是由 R、G、B 三個數字共同決定的,而不是單個分量。

詞向量也是一樣,一個 100 維的向量,就像一個 100 色的“調色盤”,每個維度都是一個“基礎顏色”,最終的“語義顏色”是所有“基礎顏色”混合的結果。


如何選擇維度?

維度是你自己設定的超參數(Hyperparameter),但它不是完全隨便寫的,需要根據任務、數據量、計算資源來選擇。

常見的維度選擇

  • 50維、100維、200維、300維:這是非常經典的范圍。
    • Google 的 Word2Vec 模型通常使用 100-300 維。
    • Stanford 的 GloVe 模型也常用 100-300 維。
  • 更小:5維、10維、20維 —— 用于教學演示、小型實驗或資源極度受限的場景。
  • 更大:512維、768維、1024維 —— 現代大型預訓練模型(如 BERT、GPT)的詞向量維度。
維度大小優點缺點適用場景
小 (如 5-50)計算快,內存占用小,模型小表達能力弱,可能學不到復雜語義教學、小型實驗、嵌入式設備
中 (如 100-300)表達能力足夠強,計算效率高-最常用,大多數 NLP 任務的首選
大 (如 512+)表達能力極強,能捕捉更細微的語義計算慢,內存占用大,需要海量數據訓練大型預訓練模型、追求極致性能

建議

  • 學習/實驗:從 5-10 維開始,便于觀察和理解。
  • 實際項目:直接用 100 或 300 維,這是經過驗證的“黃金標準”。

3. 深度學習中的NLP的特征輸入

? 深度學習使用分布式單詞表示技術(也稱詞嵌入表示),通過查看所使用的單詞的周圍單詞(即上下文)來學習單詞表示。這種表示方式將詞表示為一個粘稠的序列,在保留詞上下文信息同時,避免維度過大導致的計算困難。

3.1 稠密編碼(特征嵌入)

稠密編碼(Dense Encoding)是一種將符號(如單詞、句子、圖像等)表示為低維、連續、實數向量的表示方法。其核心特征是:

  • 低維:向量的維度相對較低,通常為幾十到幾百維(如 50、100、300 維),遠小于詞表大小。
  • 稠密:向量中的每個元素都是非零的實數(如 0.23, -1.45, 0.89),與稀疏向量(如 One-Hot)形成鮮明對比。
  • 連續:向量元素取值于實數域,支持梯度計算,可參與神經網絡的端到端訓練。
  • 分布式表示(Distributed Representation):語義信息分布在整個向量的所有維度上,而非集中在某一個維度。

與稀疏編碼的對比

特性稠密編碼(Dense)稀疏編碼(Sparse,如 One-Hot)
維度低維(如 100)高維(等于詞表大小,如 10,000)
向量值大部分非零,實數僅一個 1,其余為 0
存儲效率高(存儲 100 個浮點數)低(存儲 10,000 個整數,但有效信息僅一個)
語義表達能表達語義相似性(通過向量距離)無法表達語義,所有詞向量正交
可學習性支持梯度更新,可參與訓練通常固定,不可學習

詞向量(Word Embedding)是稠密編碼在自然語言處理中最典型、最核心的應用形式。

3.2 詞嵌入算法

Embedding Layer(嵌入層) 是深度學習,自然語言處理(NLP)中一個核心的神經網絡層,其主要功能是將離散的類別型輸入(如單詞、字符、類別標簽等)映射為低維、連續、稠密的實數向量。這種向量表示被稱為“嵌入”(Embedding)。

簡單來說,Embedding Layer 是一個可學習的查找表(Learnable Lookup Table),它將每個類別(如詞匯表中的一個詞)關聯到一個固定長度的向量,并且這些向量在模型訓練過程中會不斷被優化,以更好地服務于最終的任務(如語言建模、文本分類等)。

那么怎么得到詞向量?

可以使用nn.Embedding,它 是 PyTorch 中的一個神經網絡層,它的作用就是查找并返回詞向量。你可以把它想象成一個巨大的查表工具字典

API

nn.Embedding(num_embeddings, embedding_dim)

  • num_embeddings: 詞表大小(比如 10000)
  • embedding_dim: 每個詞向量的維度(比如 5)

PyTorch 會自動創建一個形狀為 (10000, 5)權重矩陣(可以理解為一個表格)。

這個矩陣的每一行,就對應一個詞的向量。初始化時,這些向量是隨機的(或按某種規則初始化,常用均勻分布和正態分布)。

使用

輸入一個“詞的編號”(索引)

  • 你不能直接把“北京”這個字扔給 Embedding
  • 你必須先把它轉換成一個數字編號(index),比如“北京”對應 idx=5
  • 所以輸入是一個 LongTensor,比如 torch.LongTensor([5])

輸出對應的“詞向量”

  • Embedding 層會去它內部的 (10000, 5) 表格中,找到第 5 行。
  • 返回這一整行,也就是“北京”這個詞的 5 維向量。
  • 輸出形狀是 (1, 5)

關鍵點

  • nn.Embedding 本身不進行復雜的計算(不像 Linear 層有矩陣乘法),它本質上是一個高效的查表操作(也叫“嵌入查找”)。
  • 這個“詞向量表”(權重矩陣)是可學習的參數
    • 在訓練過程中(比如訓練一個語言模型),模型會根據任務目標(如預測下一個詞)不斷調整這些向量。
    • 最終,這些向量會自動學習到詞語的語義信息。

代碼示例:

import torch
import torch.nn as nn
import jieba# 1. 原始文本
text = '北京冬奧的進度條已經過半,不少外國運動員在完成自己的比賽后踏上歸途。'# 2. 分詞
words = jieba.lcut(text)
print("分詞結果:", words)
# 輸出: ['北京', '冬奧', '的', '進度條', '已經', '過半', ',', '不少', '外國', '運動員', '在', '完成', '自己', '的', '比賽', '后', '踏上', '歸途', '。']# 3. 構建詞表(去重)并創建索引映射
# 關鍵:先去重,然后轉換為有序列表,再用 enumerate 賦予索引
words_set = list(set(words))
print("去重后的詞表:", words_set)# 創建 word2idx 和 idx2word
word2idx = {}
idx2word = {}
for i, word in enumerate(words_set):word2idx[word] = iidx2word[i] = wordprint("word2idx 映射:", word2idx)
print("idx2word 映射:", idx2word)# 4. 創建 Embedding 層
vocab_size = len(words_set)  # 詞表大小
embedding_dim = 5            # 詞向量維度
embedding = nn.Embedding(vocab_size, embedding_dim)print("\nEmbedding 層:", embedding)
# 輸出: Embedding(18, 5) 表示有18個詞,每個5維
print("Embedding 權重形狀:", embedding.weight.shape)  # 應該是 (18, 5)# 5. 查找并打印每個詞的詞向量
print("\n各詞的詞向量:")
for word in words:idx = word2idx[word]  # 獲取詞的編號# 注意:embedding 輸入必須是 LongTensoridx_tensor = torch.LongTensor([idx])embedding_vector = embedding(idx_tensor)  # 返回形狀為 (1, 5) 的張量print(f"{word} (idx={idx}) 的詞向量: {embedding_vector.squeeze().tolist()}")# 6. 單獨查找 '過半' 的詞向量
if '過半' in word2idx:idx = word2idx['過半']print(f"\n'過半' 的編號是: {idx}")embedding_vector = embedding(torch.LongTensor([idx]))print(f"'過半' 的詞向量: {embedding_vector.squeeze().tolist()}")
else:print("\n'過半' 不在詞表中!")  # 理論上不會發生

輸出(隨機初始化,每次不同):

分詞結果: ['北京', '冬奧', '的', '進度條', '已經', '過半', ',', '不少', '外國', '運動員', '在', '完成', '自己', '的', '比賽', '后', '踏上', '歸途', '。']
去重后的詞表: ['完成', '北京', '已經', '進度條', ',', '歸途', '不少', '自己', '踏上', '過半', '后', '的', '外國', '。', '運動員', '在', '冬奧', '比賽', '自己']
word2idx 映射: {'完成': 0, '北京': 1, '已經': 2, '進度條': 3, ',': 4, '歸途': 5, '不少': 6, '自己': 7, '踏上': 8, '過半': 9, '后': 10, '的': 11, '外國': 12, '。': 13, '運動員': 14, '在': 15, '冬奧': 16, '比賽': 17}
idx2word 映射: {0: '完成', 1: '北京', 2: '已經', 3: '進度條', 4: ',', 5: '歸途', 6: '不少', 7: '自己', 8: '踏上', 9: '過半', 10: '后', 11: '的', 12: '外國', 13: '。', 14: '運動員', 15: '在', 16: '冬奧', 17: '比賽'}Embedding 層: Embedding(18, 5)
Embedding 權重形狀: torch.Size([18, 5])各詞的詞向量:
北京 (idx=1) 的詞向量: [0.2143, -0.4567, 0.8912, -0.3456, 0.1234]
冬奧 (idx=16) 的詞向量: [-0.1234, 0.5678, -0.2345, 0.6789, -0.4567]
的 (idx=11) 的詞向量: [0.3456, -0.6789, 0.4567, -0.7890, 0.5678]
...'過半' 的編號是: 9
'過半' 的詞向量: [0.5678, -0.1234, 0.3456, -0.2345, 0.7890]

這些數字就是“北京”、“冬奧”等詞當前的詞向量表示。隨著模型訓練,這些數字會不斷調整,直到能最好地完成任務(如預測下一個詞)。

3.3 Word2Vec (2013, Google) (詞向量訓練方法)

Word2Vec 是一個淺層神經網絡模型,它通過兩個巧妙的“代理任務”(Proxy Tasks)來學習詞向量:

方法一:CBOW (Continuous Bag-of-Words)

  • 任務:根據上下文詞,預測中間的中心詞
    • 輸入:[“北京”, “的”, “首都”]
    • 輸出:預測 “城市”
  • 原理:為了讓模型準確預測“城市”,它就必須給“北京”、“的”、“首都”這些詞分配合適的向量,使得它們的向量之和(或平均)能最好地代表“城市”的含義。在這個過程中,詞向量就被學習出來了。

代碼示例:

import torch
import torch.nn as nn
import torch.optim as optim
from collections import Counter
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity# ======================
# 1. 數據預處理與詞匯表構建
# ======================
text = "北京 是 中國的 首都 北京 有 故宮 上海 是 中國的 經濟 中心 上海 有 外灘"
tokens = text.split()
print("Tokens:", tokens)# 構建有序詞表
word_counts = Counter(tokens)
vocab = sorted(word_counts.keys())  # 按字母排序,確保可復現
word_to_idx = {word: idx for idx, word in enumerate(vocab)}
idx_to_word = {idx: word for idx, word in enumerate(vocab)}
VOCAB_SIZE = len(vocab)
EMBEDDING_DIM = 10
CONTEXT_SIZE = 2  # 前后各2個詞print(f"詞匯表大小: {VOCAB_SIZE}, 詞匯: {vocab}")# --------------------------
# 構造訓練數據(上下文 -> 中心詞)
# --------------------------
def make_cbow_data(tokens, context_size):data = []for i in range(context_size, len(tokens) - context_size):context = tokens[i-context_size:i] + tokens[i+1:i+context_size+1]target = tokens[i]data.append((context, target))return datacbow_data = make_cbow_data(tokens, CONTEXT_SIZE)
print("CBOW 訓練樣本示例:", cbow_data[:3])# --------------------------
# CBOW 模型定義
# --------------------------
class CBOW(nn.Module):def __init__(self, vocab_size, embedding_dim):super(CBOW, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim)self.fc = nn.Linear(embedding_dim, vocab_size)def forward(self, context_indices):# context_indices: (batch_size, context_len)embeds = self.embedding(context_indices)  # (B, C, D)context_vec = embeds.sum(dim=1)          # (B, D)output = self.fc(context_vec)            # (B, V)return torch.log_softmax(output, dim=1)# 初始化模型、損失、優化器
model = CBOW(VOCAB_SIZE, EMBEDDING_DIM)
loss_function = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 稍微調高學習率# --------------------------
# 訓練模型(小批量)
# --------------------------
BATCH_SIZE = 4
EPOCHS = 200for epoch in range(EPOCHS):total_loss = 0.0# 簡單的小批量處理for i in range(0, len(cbow_data), BATCH_SIZE):batch = cbow_data[i:i+BATCH_SIZE]context_batch = []target_batch = []for context, target in batch:context_idx = [word_to_idx[w] for w in context]context_batch.append(context_idx)target_batch.append(word_to_idx[target])# 轉為 Tensorcontext_tensor = torch.LongTensor(context_batch)  # (B, 4)target_tensor = torch.LongTensor(target_batch)    # (B,)# 前向傳播log_probs = model(context_tensor)loss = loss_function(log_probs, target_tensor)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()if epoch % 50 == 0:print(f"Epoch {epoch}, Average Loss: {total_loss/len(cbow_data):.4f}")# 獲取訓練后的詞向量矩陣
trained_embeddings = model.embedding.weight.data.numpy()  # 或 model_cbow.embedding.weight
print("詞向量形狀:", trained_embeddings.shape)  # (VOCAB_SIZE, EMBEDDING_DIM)# 查看“北京”和“上海”的向量
vec_beijing = trained_embeddings[word_to_idx["北京"]]
vec_shanghai = trained_embeddings[word_to_idx["上海"]]# 計算余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
sim = cosine_similarity([vec_beijing], [vec_shanghai])[0][0]
print(f"'北京' 和 '上海' 的余弦相似度: {sim:.4f}")# 輸出所有詞向量(可選)
for word, idx in word_to_idx.items():print(f"{word}: {trained_embeddings[idx][:4]}...")  # 顯示前4維

方法二:Skip-Gram

  • 任務:根據中心詞,預測它周圍的上下文詞
    • 輸入:“城市”
    • 輸出:預測 “北京”, “的”, “首都” (或其中一部分)
  • 原理:為了讓模型能從“城市”預測出“北京”和“首都”,它就必須讓“城市”、“北京”、“首都”的向量在空間中彼此接近。

Word2Vec 的核心:它不關心預測任務本身有多準確,它關心的是在完成這個任務時,詞向量表nn.Embedding 層的權重)是如何被調整的。最終,這個被調整好的詞向量表就是我們想要的。

import torch
import torch.nn as nn
import torch.optim as optim
from collections import Counter
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity# ======================
# 1. 數據預處理
# ======================
text = "北京 是 中國的 首都 北京 有 故宮 上海 是 中國的 經濟 中心 上海 有 外灘"
tokens = text.split()
print("Tokens:", tokens)vocab = sorted(set(tokens))
word_to_idx = {word: idx for idx, word in enumerate(vocab)}
idx_to_word = {idx: word for idx, word in enumerate(vocab)}
VOCAB_SIZE = len(vocab)
EMBEDDING_DIM = 10
CONTEXT_SIZE = 2print(f"詞匯表大小: {VOCAB_SIZE}, 詞匯: {vocab}")# --------------------------
# 構造 Skip-Gram 數據(動態窗口)
# --------------------------
def make_skipgram_data(tokens, context_size):data = []for i in range(context_size, len(tokens) - context_size):target = tokens[i]#  使用 CONTEXT_SIZE 動態構造上下文context = tokens[i - context_size:i] + tokens[i+1:i + context_size + 1]for ctx_word in context:data.append((target, ctx_word))return dataskipgram_data = make_skipgram_data(tokens, CONTEXT_SIZE)
print("Skip-Gram 訓練樣本示例:", skipgram_data[:6])# --------------------------
# Skip-Gram 模型
# --------------------------
class SkipGram(nn.Module):def __init__(self, vocab_size, embedding_dim):super(SkipGram, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim)self.fc = nn.Linear(embedding_dim, vocab_size)def forward(self, target_idx):embed = self.embedding(target_idx)output = self.fc(embed)return torch.log_softmax(output, dim=1)# 初始化
model = SkipGram(VOCAB_SIZE, EMBEDDING_DIM)
loss_function = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 提高學習率# --------------------------
# 小批量訓練
# --------------------------
BATCH_SIZE = 4
EPOCHS = 200for epoch in range(EPOCHS):total_loss = 0.0for i in range(0, len(skipgram_data), BATCH_SIZE):batch = skipgram_data[i:i+BATCH_SIZE]target_idx = torch.LongTensor([word_to_idx[t] for t, _ in batch])context_idx = torch.LongTensor([word_to_idx[c] for _, c in batch])log_probs = model(target_idx)loss = loss_function(log_probs, context_idx)optimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()if epoch % 50 == 0:print(f"Epoch {epoch}, Loss: {total_loss:.4f}")# --------------------------
# 提取詞向量
# --------------------------
trained_embeddings = model.embedding.weight.data.numpy()
print("詞向量形狀:", trained_embeddings.shape)vec_beijing = trained_embeddings[word_to_idx["北京"]]
vec_shanghai = trained_embeddings[word_to_idx["上海"]]
sim = cosine_similarity([vec_beijing], [vec_shanghai])[0][0]
print(f"'北京' 和 '上海' 的余弦相似度: {sim:.4f}")for word, idx in word_to_idx.items():print(f"{word}: {trained_embeddings[idx][:4]}...")

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

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

相關文章

保姆級Debezium抽取SQL Server同步kafka

前言: Debezium SQL Server連接器捕獲SQL Server數據庫模式中發生的行級更改。 官方2.0文檔: Debezium connector for SQL Server :: Debezium Documentation 有關與此連接器兼容的SQL Server版本的信息,請參閱 SQL Server Database: 201…

鴻蒙安卓前端中加載丟幀:ArkWeb分析

序章:卡頓的數字世界 在每秒60幀的視覺交響樂中,每一幀都是精心編排的節拍。當這些節拍開始丟失——就像交響樂中突然靜音的提琴部——我們便遭遇了加載丟幀的數字噩夢。這不是簡單的性能下降,而是一場渲染管線的全面崩潰,是數字…

Spring Cloud Netflix學習筆記06-Zuul

文章目錄概述什么是Zuul?Zuul 能干嘛?Zuul入門案例pom依賴application.yml啟動類隱藏真實路徑概述 什么是Zuul? Zuul包含了對請求的路由(用來跳轉的)和過濾兩個最主要功能: 其中路由功能負責將外部請求轉發到具體的微服務實例上,是實現外…

c# 和 c++ 怎樣結合

c# 和 c 怎樣結合在軟件開發中,C# 和 C 通常用于不同的場景和目的,但有時需要將它們結合使用以充分利用兩種語言的優點。以下是幾種常見的方法來實現 C# 和 C 的結合:1. P/Invoke(Platform Invocation Services)P/Invo…

開源分布式數據庫(Dgraph)

Dgraph 是一款專為處理復雜關系數據設計的開源分布式圖數據庫,核心目標是提供高性能、高可擴展性的圖數據存儲與查詢能力。其設計融合了原生圖模型與分布式架構,支持 GraphQL 查詢語言,適用于社交網絡、知識圖譜、推薦系統等場景。 一、技術架…

Apache ShenYu和Nacos之間的通信原理

這是一個非常經典的服務注冊發現和動態配置管理的案例。ShenYu 作為網關,需要實時感知后端微服務的上線、下線以及其元數據信息(如 API 接口列表)的變化,同時它自身的配置也可能需要動態調整。Nacos 則作為注冊中心和配置中心,扮演了“服務電話簿”和“動態配置倉庫”的角…

強制重啟導致Ubuntu24.04LTS amd的WIFI無法使用的解決方案

強制重啟導致Ubuntu24.04LTS amd的WIFI無法使用的解決方案 前言 ? 我按下了<ctrl><alt><prtsc>組合鍵&#xff0c;然后按住<ctrl><alt>不放&#xff0c;讓我的死機的圖形化的Ubuntu強制重啟&#xff0c;然后再次打開發現&#xff0c;我的ubu…

Java基礎面試題02

引用&#xff1a;&#xff08;代碼隨想錄的八股轉免費了&#xff09;以下為網址 卡碼筆記 本文為學習以上文章的筆記&#xff0c;如果有時間推薦直接去原網址 Java中的數據類型有哪些&#xff1f;分為哪兩大類&#xff1f; (考點&#xff1a;Java數據類型及其分類) 【簡單】 基…

RabbitMQ:SpringAMQP Fanout Exchange(扇型交換機)

目錄一、案例需求二、基礎配置三、代碼實現扇形交換機也叫做廣播交換機&#xff0c;通過交換機將消息發送給所有的隊列。 生產者源碼 消費者源碼 一、案例需求 在RabbitMQ控制臺中&#xff0c;聲明隊列fanout.queue1和fanout.queue2。在RabbitMQ控制臺中&#xff0c;聲明交換…

深度解析DeepSeek V3.1 :6850 億參數開源模型如何以 71.6% 編碼得分、68 倍成本優勢重構全球 AI 競爭格局

深度解析DeepSeek V3.1 &#xff1a;6850 億參數開源模型如何以 71.6% 編碼得分、68 倍成本優勢重構全球 AI 競爭格局當DeepSeek悄然將其 6850 億參數的 V3.1 模型上傳至 Hugging Face 平臺時&#xff0c;這個看似低調的舉動卻在全球 AI 領域投下了一顆 “深水炸彈”。這款融合…

Java 大視界 -- Java 大數據在智能安防視頻監控系統中的視頻內容理解與智能預警升級(401)

Java 大視界 -- Java 大數據在智能安防視頻監控系統中的視頻內容理解與智能預警升級&#xff08;401&#xff09;引言&#xff1a;正文&#xff1a;一、傳統安防監控的 “三重困局”&#xff1a;看不全、看不懂、反應慢1.1 人工盯屏 “力不從心”1.1.1 攝像頭密度與人力的矛盾1…

ansible playbook 實戰案例roles | 實現基于node_exporter的節點部署

文章目錄一、核心功能描述二、roles內容2.1 文件結構2.2 主配置文件2.3 tasks文件內容2.4 vars文件內容免費個人運維知識庫&#xff0c;歡迎您的訂閱&#xff1a;literator_ray.flowus.cn 一、核心功能描述 這個 Ansible Role 的核心功能是&#xff1a;?自動化部署 Prometheu…

.NET Core MongoDB 查詢數據異常及解決

.NET Core 查詢 MongoDB異常消息Element _class does not match any field or property of class WebApiServer.Model.Enity.Ypxxx.圖中寫的修改實際是查詢分頁出現的異常&#xff0c;異常是查詢轉換為List<T>時出現的&#xff1a; 這個錯誤通常發生在MongoDB文檔中包含的…

政策技術雙輪驅動智慧燈桿市場擴容,塔能科技破解行業痛點

在新型城市基礎設施建設不斷加速&#xff0c;以及“雙碳”戰略持續深化這樣的雙重背景之下&#xff0c;智慧燈桿市場恰恰迎來了政策紅利得以釋放、技術出現迭代突破并且需求在持續升級的極為難得的黃金發展時期。智慧城市建設 的核心承載從國家層面所開展的全域智能化改造規劃&…

JetBrains Mono字體

好的,我們來詳細解析一下 JetBrains Mono 的 8 種主要字體風格(實際上官方提供了 9 種字重,但通常我們討論其核心風格)及其區別。 這些風格的區別主要體現在兩個方面:字重 和 字形。 核心區別:字重 字重就是字體的粗細程度。JetBrains Mono 提供了從細到極粗的多種選擇…

MySQL 分頁查詢:用 LIMIT 高效處理大量數據

MySQL 分頁查詢&#xff1a;用 LIMIT 高效處理大量數據 在實際開發中&#xff0c;當查詢結果包含成百上千條記錄時&#xff0c;一次性展示所有數據會導致加載緩慢、用戶體驗差。分頁查詢能將數據分段展示&#xff0c;既減輕服務器壓力&#xff0c;又方便用戶瀏覽。MySQL 中通過…

GraphQL 與 REST 在微服務架構中的對比與設計實踐

GraphQL 與 REST 在微服務架構中的對比與設計實踐 隨著微服務架構的普及&#xff0c;API 設計已經成為系統性能、可維護性和開發效率的關鍵。REST&#xff08;Representational State Transfer&#xff09;作為傳統的無狀態架構風格&#xff0c;擁有簡單、成熟的生態&#xff1…

WebSocket通信:sockjs與stomp.js的完美搭檔

sockjs 和 stomp.js 是 WebSocket 通信場景中功能互補的兩個庫,它們的結合能解決實際開發中的關鍵問題,因此常被一起使用。 1. 兩者的核心作用與聯系 sockjs:是一個 傳輸層庫,解決的是“如何在各種環境下建立可靠的雙向通信連接”的問題。 WebSocket 協議本身存在兼容性限…

元宇宙的網絡基礎設施:5G 與 6G 的關鍵作用

1 5G 技術對元宇宙的支撐作用1.1 高帶寬保障沉浸式內容傳輸5G 技術的超大帶寬特性為元宇宙的海量數據傳輸提供了基礎支撐。元宇宙中的沉浸式體驗依賴于高清視頻、3D 模型、實時交互數據等大容量內容&#xff0c;普通 4G 網絡的帶寬&#xff08;約 100Mbps&#xff09;難以滿足需…

【39頁PPT】大模型DeepSeek在運維場景中的應用(附下載方式)

篇幅所限&#xff0c;本文只提供部分資料內容&#xff0c;完整資料請看下面鏈接 https://download.csdn.net/download/2501_92808811/91694206 資料解讀&#xff1a;【39頁PPT】大模型DeepSeek在運維場景中的應用 詳細資料請看本解讀文章的最后內容。大模型技術在當下的科技領…