# 導入PyTorch核心庫
import torch
# 導入神經網絡模塊
import torch.nn as nn
# 導入優化器模塊
import torch.optim as optim
# 導入函數式API模塊
import torch.nn.functional as F
# 導入數據集和數據加載器
from torch.utils.data import Dataset, DataLoader
# 導入NumPy數值計算庫
import numpy as np
# 導入matplotlib繪圖庫
import matplotlib.pyplot as plt
# 導入t-SNE降維算法
from sklearn.manifold import TSNE
# 導入PCA降維算法
from sklearn.decomposition import PCA
# 導入jieba中文分詞庫
import jieba
# 導入正則表達式庫
import re
# 導入計數器和默認字典
from collections import Counter, defaultdict
# 導入進度條庫
from tqdm import tqdm
# 導入序列化庫
import pickle
# 導入操作系統接口
import os
# 導入隨機數生成庫
import random# 設置matplotlib使用中文字體
plt.rcParams['font.sans-serif'] = ['SimHei']
# 設置matplotlib正確顯示負號
plt.rcParams['axes.unicode_minus'] = Falseclass TextProcessor:"""文本預處理器類 - 負責文本清理、分詞、詞匯表構建等功能"""def __init__(self, min_count=5, window_size=5):"""初始化文本預處理器Args:min_count: 詞匯最小出現次數,低于此次數的詞將被過濾window_size: 窗口大小,用于確定上下文范圍"""# 設置詞匯最小出現次數閾值self.min_count = min_count# 設置窗口大小self.window_size = window_size# 初始化詞匯到索引的映射字典self.word2idx = {}# 初始化索引到詞匯的映射字典self.idx2word = {}# 初始化詞匯計數器self.word_counts = Counter()# 初始化詞匯表大小self.vocab_size = 0def clean_text(self, text):"""清理文本內容Args:text: 輸入的原始文本Returns:清理后的文本"""# 使用正則表達式移除特殊字符,僅保留中文、英文、數字和空格text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s]', '', text)# 去除首尾空格并返回return text.strip()def tokenize(self, text):"""對文本進行分詞處理Args:text: 輸入文本Returns:分詞后的詞匯列表"""# 首先清理文本text = self.clean_text(text)# 使用jieba進行中文分詞tokens = list(jieba.cut(text))# 過濾掉空白符和長度小于等于1的詞,返回有效詞匯列表return [token for token in tokens if token.strip() and len(token) > 1]def build_vocab(self, texts):"""構建詞匯表Args:texts: 輸入的文本列表"""# 打印詞匯表構建開始提示print("正在構建詞匯表...")# 遍歷所有文本,統計詞頻for text in tqdm(texts, desc="統計詞頻"):# 對當前文本進行分詞tokens = self.tokenize(text)# 更新詞匯計數器self.word_counts.update(tokens)# 根據最小出現次數過濾詞匯,構建有效詞匯列表vocab_words = [word for word, count in self.word_counts.items() if count >= self.min_count]# 構建詞匯到索引的映射字典self.word2idx = {word: idx for idx, word in enumerate(vocab_words)}# 構建索引到詞匯的映射字典self.idx2word = {idx: word for word, idx in self.word2idx.items()}# 更新詞匯表大小self.vocab_size = len(vocab_words)# 打印詞匯表統計信息print(f"詞匯表大小: {self.vocab_size}")print(f"總詞數: {sum(self.word_counts.values())}")def text_to_indices(self, text):"""將文本轉換為索引序列Args:text: 輸入文本Returns:詞匯索引序列"""# 對文本進行分詞tokens = self.tokenize(text)# 將詞匯轉換為索引,忽略不在詞匯表中的詞return [self.word2idx[token] for token in tokens if token in self.word2idx]def generate_training_data(self, texts, model_type='cbow'):"""生成訓練數據Args:texts: 輸入文本列表model_type: 模型類型('cbow'或'skipgram')Returns:訓練數據列表"""# 初始化訓練數據列表training_data = []# 打印訓練數據生成開始提示print(f"生成{model_type.upper()}訓練數據...")# 遍歷所有文本for text in tqdm(texts, desc="處理文本"):# 將文本轉換為索引序列indices = self.text_to_indices(text)# 如果序列長度不夠構建窗口,跳過此文本if len(indices) < self.window_size * 2 + 1:continue# 遍歷序列中的每個可能的中心詞位置for i in range(self.window_size, len(indices) - self.window_size):# 根據模型類型生成不同的訓練樣本if model_type == 'cbow':# CBOW模型:使用上下文詞預測中心詞# 構建上下文詞索引(中心詞前后各window_size個詞)context = (indices[i-self.window_size:i] + indices[i+1:i+self.window_size+1])# 中心詞作為目標target = indices[i]# 添加訓練樣本(上下文,中心詞)training_data.append((context, target))else:# Skip-gram模型:使用中心詞預測上下文詞# 當前位置的詞作為中心詞center_word = indices[i]# 遍歷窗口內的所有上下文詞for j in range(i-self.window_size, i+self.window_size+1):# 跳過中心詞本身if j != i:# 獲取上下文詞context_word = indices[j]# 添加訓練樣本(中心詞,上下文詞)training_data.append((center_word, context_word))# 打印生成的訓練樣本數量print(f"生成訓練樣本數: {len(training_data)}")# 返回訓練數據return training_dataclass CBOWDataset(Dataset):"""CBOW模型數據集類 - 繼承自PyTorch的Dataset類"""def __init__(self, training_data):"""初始化CBOW數據集Args:training_data: 訓練數據列表"""# 存儲訓練數據self.training_data = training_datadef __len__(self):"""返回數據集大小Returns:數據集的樣本數量"""# 返回訓練數據的長度return len(self.training_data)def __getitem__(self, idx):"""獲取指定索引的數據樣本Args:idx: 樣本索引Returns:上下文張量和目標張量"""# 獲取指定索引的上下文和目標context, target = self.training_data[idx]# 將上下文轉換為長整型張量,目標轉換為長整型張量return torch.tensor(context, dtype=torch.long), torch.tensor(target, dtype=torch.long)class SkipGramDataset(Dataset):"""Skip-gram模型數據集類 - 繼承自PyTorch的Dataset類"""def __init__(self, training_data):"""初始化Skip-gram數據集Args:training_data: 訓練數據列表"""# 存儲訓練數據self.training_data = training_datadef __len__(self):"""返回數據集大小Returns:數據集的樣本數量"""# 返回訓練數據的長度return len(self.training_data)def __getitem__(self, idx):"""獲取指定索引的數據樣本Args:idx: 樣本索引Returns:中心詞張量和上下文張量"""# 獲取指定索引的中心詞和上下文詞center, context = self.training_data[idx]# 將中心詞和上下文詞轉換為長整型張量return torch.tensor(center, dtype=torch.long), torch.tensor(context, dtype=torch.long)class CBOWModel(nn.Module):"""CBOW模型類 - 繼承自PyTorch的nn.Module"""def __init__(self, vocab_size, embedding_dim):"""初始化CBOW模型Args:vocab_size: 詞匯表大小embedding_dim: 詞向量維度"""# 調用父類構造函數super(CBOWModel, self).__init__()# 創建詞嵌入層,將詞匯索引映射為詞向量self.embedding = nn.Embedding(vocab_size, embedding_dim)# 創建線性層,將詞向量映射為詞匯表大小的輸出self.linear = nn.Linear(embedding_dim, vocab_size)def forward(self, context):"""前向傳播函數Args:context: 上下文詞索引張量,形狀為(batch_size, context_size)Returns:輸出張量,形狀為(batch_size, vocab_size)"""# 通過嵌入層獲取上下文詞的詞向量,形狀為(batch_size, context_size, embedding_dim)embeddings = self.embedding(context)# 計算上下文詞向量的平均值,形狀為(batch_size, embedding_dim)context_mean = torch.mean(embeddings, dim=1)# 通過線性層映射到詞匯表大小,形狀為(batch_size, vocab_size)output = self.linear(context_mean)# 返回輸出結果return outputclass SkipGramModel(nn.Module):"""Skip-gram模型類 - 繼承自PyTorch的nn.Module"""def __init__(self, vocab_size, embedding_dim):"""初始化Skip-gram模型Args:vocab_size: 詞匯表大小embedding_dim: 詞向量維度"""# 調用父類構造函數super(SkipGramModel, self).__init__()# 創建詞嵌入層,將詞匯索引映射為詞向量self.embedding = nn.Embedding(vocab_size, embedding_dim)# 創建線性層,將詞向量映射為詞匯表大小的輸出self.linear = nn.Linear(embedding_dim, vocab_size)def forward(self, center_word):"""前向傳播函數Args:center_word: 中心詞索引張量,形狀為(batch_size,)Returns:輸出張量,形狀為(batch_size, vocab_size)"""# 通過嵌入層獲取中心詞的詞向量,形狀為(batch_size, embedding_dim)embedded = self.embedding(center_word)# 通過線性層映射到詞匯表大小,形狀為(batch_size, vocab_size)output = self.linear(embedded)# 返回輸出結果return outputclass Word2Vec:"""Word2Vec主類 - 封裝了完整的Word2Vec模型訓練和使用功能"""def __init__(self, embedding_dim=100, window_size=5, min_count=5, model_type='cbow'):"""初始化Word2Vec模型Args:embedding_dim: 詞向量維度window_size: 窗口大小min_count: 詞匯最小出現次數model_type: 模型類型('cbow'或'skipgram')"""# 設置詞向量維度self.embedding_dim = embedding_dim# 設置窗口大小self.window_size = window_size# 設置最小詞頻self.min_count = min_count# 設置模型類型self.model_type = model_type# 創建文本處理器實例self.processor = TextProcessor(min_count, window_size)# 初始化模型為空self.model = None# 設置計算設備(GPU優先,否則使用CPU)self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# 打印使用的設備信息print(f"使用設備: {self.device}")def create_sample_corpus(self):"""創建示例語料庫Returns:擴展后的語料庫列表"""# 定義示例語料庫corpus = ["我喜歡吃蘋果和香蕉","蘋果是一種很好的水果","香蕉含有豐富的維生素","我每天都會吃水果","水果對健康很有益","蘋果和香蕉都很美味","我喜歡在早上吃水果","健康的生活需要多吃水果","蘋果香蕉都是我喜歡的水果","維生素對身體健康很重要","我喜歡看電影和聽音樂","電影院里播放著精彩的電影","音樂能夠讓人放松心情","我每天都會聽音樂","音樂對情緒很有幫助","電影和音樂都很有趣","我喜歡在晚上看電影","娛樂活動能夠緩解壓力","電影音樂都是我喜歡的娛樂","放松心情對身心健康很重要","學習是一件很重要的事情","我喜歡學習新的知識","知識能夠讓人變得更聰明","學校是學習知識的地方","老師會教給我們很多知識","學習需要認真和努力","我每天都會學習新東西","教育對個人發展很重要","學習知識是學生的職責","努力學習才能取得好成績","運動對身體健康很重要","我喜歡跑步和游泳","跑步能夠鍛煉身體","游泳是一種很好的運動","運動能夠增強體質","我每天都會做運動","健身房里有很多運動器材","堅持運動能夠保持健康","跑步游泳都是我喜歡的運動","鍛煉身體需要持之以恒"]# 初始化擴展后的語料庫extended_corpus = []# 重復語料庫內容10次以增加數據量for _ in range(10):# 將原始語料庫添加到擴展語料庫中extended_corpus.extend(corpus)# 返回擴展后的語料庫return extended_corpusdef train(self, texts, epochs=100, batch_size=64, learning_rate=0.001):"""訓練Word2Vec模型Args:texts: 訓練文本列表epochs: 訓練輪數batch_size: 批次大小learning_rate: 學習率"""# 打印訓練開始提示print(f"開始訓練{self.model_type.upper()}模型...")# 使用文本處理器構建詞匯表self.processor.build_vocab(texts)# 生成訓練數據training_data = self.processor.generate_training_data(texts, self.model_type)# 根據模型類型創建相應的數據集和模型if self.model_type == 'cbow':# 創建CBOW數據集dataset = CBOWDataset(training_data)# 創建CBOW模型并移動到指定設備self.model = CBOWModel(self.processor.vocab_size, self.embedding_dim).to(self.device)else:# 創建Skip-gram數據集dataset = SkipGramDataset(training_data)# 創建Skip-gram模型并移動到指定設備self.model = SkipGramModel(self.processor.vocab_size, self.embedding_dim).to(self.device)# 創建數據加載器dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)# 創建Adam優化器optimizer = optim.Adam(self.model.parameters(), lr=learning_rate)# 創建交叉熵損失函數criterion = nn.CrossEntropyLoss()# 初始化損失記錄列表losses = []# 開始訓練循環for epoch in range(epochs):# 初始化當前輪次的總損失total_loss = 0# 初始化批次計數器num_batches = 0# 創建進度條progress_bar = tqdm(dataloader, desc=f'Epoch {epoch+1}/{epochs}')# 遍歷數據批次for batch in progress_bar:# 根據模型類型處理批次數據if self.model_type == 'cbow':# CBOW模型:獲取上下文和目標context, target = batch# 將數據移動到指定設備context = context.to(self.device)target = target.to(self.device)# 清零梯度optimizer.zero_grad()# 前向傳播output = self.model(context)# 計算損失loss = criterion(output, target)else:# Skip-gram模型:獲取中心詞和上下文center, context = batch# 將數據移動到指定設備center = center.to(self.device)context = context.to(self.device)# 清零梯度optimizer.zero_grad()# 前向傳播output = self.model(center)# 計算損失loss = criterion(output, context)# 反向傳播loss.backward()# 更新參數optimizer.step()# 累計損失total_loss += loss.item()# 增加批次計數num_batches += 1# 更新進度條顯示progress_bar.set_postfix({'Loss': f'{loss.item():.4f}'})# 計算平均損失avg_loss = total_loss / num_batches# 記錄損失值losses.append(avg_loss)# 每10個epoch打印一次損失if (epoch + 1) % 10 == 0:print(f'Epoch [{epoch+1}/{epochs}], Average Loss: {avg_loss:.4f}')# 繪制訓練損失曲線self.plot_loss_curve(losses)# 打印訓練完成提示print("訓練完成!")def get_word_vector(self, word):"""獲取單詞的詞向量Args:word: 輸入單詞Returns:詞向量數組或None"""# 檢查詞匯是否在詞匯表中if word not in self.processor.word2idx:return None# 獲取詞匯的索引word_idx = self.processor.word2idx[word]# 創建詞匯索引張量并移動到指定設備word_tensor = torch.tensor([word_idx], dtype=torch.long).to(self.device)# 在不計算梯度的情況下獲取詞向量with torch.no_grad():# 通過嵌入層獲取詞向量embedding = self.model.embedding(word_tensor)# 將張量轉換為numpy數組并展平return embedding.cpu().numpy().flatten()def find_similar_words(self, word, top_k=10):"""查找與給定詞匯最相似的詞匯Args:word: 目標詞匯top_k: 返回最相似的k個詞匯Returns:相似詞匯列表,每個元素為(詞匯, 相似度)"""# 檢查詞匯是否在詞匯表中if word not in self.processor.word2idx:print(f"詞匯 '{word}' 不在詞典中")return []# 獲取目標詞匯的詞向量target_vector = self.get_word_vector(word)# 如果獲取失敗,返回空列表if target_vector is None:return []# 初始化相似度列表similarities = []# 遍歷詞匯表中的所有詞匯for w in self.processor.word2idx:# 跳過目標詞匯本身if w != word:# 獲取當前詞匯的詞向量vector = self.get_word_vector(w)# 如果成功獲取詞向量if vector is not None:# 計算余弦相似度similarity = np.dot(target_vector, vector) / (np.linalg.norm(target_vector) * np.linalg.norm(vector))# 添加到相似度列表similarities.append((w, similarity))# 按相似度降序排序similarities.sort(key=lambda x: x[1], reverse=True)# 返回前top_k個最相似的詞匯return similarities[:top_k]def word_analogy(self, word1, word2, word3, top_k=5):"""詞匯類比功能 (word1 - word2 + word3 = ?)Args:word1: 第一個詞匯word2: 第二個詞匯word3: 第三個詞匯top_k: 返回最相似的k個結果Returns:類比結果列表,每個元素為(詞匯, 相似度)"""# 將三個詞匯組成列表words = [word1, word2, word3]# 初始化詞向量列表vectors = []# 遍歷三個詞匯for word in words:# 檢查詞匯是否在詞匯表中if word not in self.processor.word2idx:print(f"詞匯 '{word}' 不在詞典中")return []# 獲取詞匯的詞向量vector = self.get_word_vector(word)# 如果獲取失敗,返回空列表if vector is None:return []# 添加到詞向量列表vectors.append(vector)# 計算類比向量 (word1 - word2 + word3)target_vector = vectors[0] - vectors[1] + vectors[2]# 初始化相似度列表similarities = []# 遍歷詞匯表中的所有詞匯for w in self.processor.word2idx:# 跳過輸入的三個詞匯if w not in words:# 獲取當前詞匯的詞向量vector = self.get_word_vector(w)# 如果成功獲取詞向量if vector is not None:# 計算與目標向量的余弦相似度similarity = np.dot(target_vector, vector) / (np.linalg.norm(target_vector) * np.linalg.norm(vector))# 添加到相似度列表similarities.append((w, similarity))# 按相似度降序排序similarities.sort(key=lambda x: x[1], reverse=True)# 返回前top_k個最相似的詞匯return similarities[:top_k]def visualize_embeddings(self, words=None, method='tsne'):"""可視化詞向量Args:words: 要可視化的詞匯列表,如果為None則使用最頻繁的詞匯method: 降維方法('tsne'或'pca')"""# 如果沒有指定詞匯,使用最頻繁的50個詞匯if words is None:words = [word for word, _ in self.processor.word_counts.most_common(50)]# 初始化詞向量列表和有效詞匯列表vectors = []valid_words = []# 遍歷指定的詞匯for word in words:# 獲取詞匯的詞向量vector = self.get_word_vector(word)# 如果成功獲取詞向量if vector is not None:# 添加到詞向量列表vectors.append(vector)# 添加到有效詞匯列表valid_words.append(word)# 如果沒有可用的詞向量,返回if len(vectors) == 0:print("沒有可用的詞向量")return# 將詞向量列表轉換為numpy數組vectors = np.array(vectors)# 根據指定方法進行降維if method == 'tsne':# 使用t-SNE降維到2維reducer = TSNE(n_components=2, random_state=42)vectors_2d = reducer.fit_transform(vectors)else:# 使用PCA降維到2維reducer = PCA(n_components=2, random_state=42)vectors_2d = reducer.fit_transform(vectors)# 創建圖形plt.figure(figsize=(12, 8))# 繪制散點圖plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1], alpha=0.7)# 為每個點添加詞匯標簽for i, word in enumerate(valid_words):plt.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]), xytext=(5, 5), textcoords='offset points')# 設置圖形標題plt.title(f'詞向量可視化 ({method.upper()})')# 設置x軸標簽plt.xlabel('維度 1')# 設置y軸標簽plt.ylabel('維度 2')# 顯示網格plt.grid(True, alpha=0.3)# 調整布局plt.tight_layout()# 保存圖形plt.savefig(f'word_embeddings_{method}.png', dpi=300, bbox_inches='tight')# 顯示圖形plt.show()def plot_loss_curve(self, losses):"""繪制訓練損失曲線Args:losses: 損失值列表"""# 創建圖形plt.figure(figsize=(10, 6))# 繪制損失曲線plt.plot(losses)# 設置圖形標題plt.title('訓練損失曲線')# 設置x軸標簽plt.xlabel('Epoch')# 設置y軸標簽plt.ylabel('Loss')# 顯示網格plt.grid(True, alpha=0.3)# 調整布局plt.tight_layout()# 保存圖形plt.savefig('training_loss.png', dpi=300, bbox_inches='tight')# 顯示圖形plt.show()def save_model(self, filepath):"""保存模型到文件Args:filepath: 保存路徑"""# 使用torch.save保存模型狀態字典和相關信息torch.save({'model_state_dict': self.model.state_dict(), # 模型參數'processor': self.processor, # 文本處理器'model_type': self.model_type, # 模型類型'embedding_dim': self.embedding_dim # 詞向量維度}, filepath)# 打印保存成功提示print(f"模型已保存到 {filepath}")def load_model(self, filepath):"""從文件加載模型Args:filepath: 模型文件路徑"""# 加載模型檢查點checkpoint = torch.load(filepath, map_location=self.device)# 恢復文本處理器self.processor = checkpoint['processor']# 恢復模型類型self.model_type = checkpoint['model_type']# 恢復詞向量維度self.embedding_dim = checkpoint['embedding_dim']# 根據模型類型創建相應的模型if self.model_type == 'cbow':# 創建CBOW模型并移動到指定設備self.model = CBOWModel(self.processor.vocab_size, self.embedding_dim).to(self.device)else:# 創建Skip-gram模型并移動到指定設備self.model = SkipGramModel(self.processor.vocab_size, self.embedding_dim).to(self.device)# 加載模型參數self.model.load_state_dict(checkpoint['model_state_dict'])# 打印加載成功提示print(f"模型已從 {filepath} 加載")def main():"""主函數 - 演示Word2Vec模型的完整使用流程"""# 打印程序標題print("=== Word2Vec 詞向量模型 ===\n")# 第一部分:訓練CBOW模型print("1. 訓練CBOW模型")# 創建CBOW模型實例cbow_model = Word2Vec(embedding_dim=100, # 詞向量維度為100window_size=5, # 窗口大小為5min_count=2, # 最小詞頻為2model_type='cbow' # 模型類型為CBOW)# 創建示例語料庫corpus = cbow_model.create_sample_corpus()# 打印語料庫統計信息print(f"語料庫大小: {len(corpus)} 個句子")# 訓練CBOW模型cbow_model.train(corpus, epochs=50, batch_size=32, learning_rate=0.001)# 第二部分:測試CBOW模型功能print("\n=== CBOW模型測試 ===")# 定義測試詞匯列表test_words = ['蘋果', '香蕉', '水果', '學習', '知識', '運動', '健康']# 遍歷測試詞匯,檢查詞向量for word in test_words:# 獲取詞匯的詞向量vector = cbow_model.get_word_vector(word)# 檢查是否成功獲取詞向量if vector is not None:print(f"'{word}' 的詞向量維度: {vector.shape}")else:print(f"'{word}' 不在詞典中")# 第三部分:測試相似詞查找功能print("\n=== 相似詞查找 ===")# 查找與"蘋果"最相似的5個詞匯similar_words = cbow_model.find_similar_words('蘋果', top_k=5)print(f"與 '蘋果' 最相似的詞:")# 打印相似詞及其相似度for word, similarity in similar_words:print(f" {word}: {similarity:.4f}")# 第四部分:測試詞匯類比功能print("\n=== 詞匯類比 ===")# 執行詞匯類比:蘋果 - 水果 + 音樂 = ?analogy_result = cbow_model.word_analogy('蘋果', '水果', '音樂', top_k=3)print("蘋果 - 水果 + 音樂 = ?")# 打印類比結果for word, similarity in analogy_result:print(f" {word}: {similarity:.4f}")# 第五部分:可視化詞向量print("\n=== 詞向量可視化 ===")# 使用t-SNE方法可視化詞向量cbow_model.visualize_embeddings(method='tsne')# 保存CBOW模型cbow_model.save_model('word2vec_cbow_model.pth')# 分隔線print("\n" + "="*50)print("2. 訓練Skip-gram模型")# 第六部分:訓練Skip-gram模型skipgram_model = Word2Vec(embedding_dim=100, # 詞向量維度為100window_size=5, # 窗口大小為5min_count=2, # 最小詞頻為2model_type='skipgram' # 模型類型為Skip-gram)# 訓練Skip-gram模型skipgram_model.train(corpus, epochs=50, batch_size=32, learning_rate=0.001)# 第七部分:測試Skip-gram模型print("\n=== Skip-gram模型測試 ===")# 查找與"蘋果"最相似的5個詞匯similar_words_sg = skipgram_model.find_similar_words('蘋果', top_k=5)print(f"Skip-gram模型中與 '蘋果' 最相似的詞:")# 打印相似詞及其相似度for word, similarity in similar_words_sg:print(f" {word}: {similarity:.4f}")# 保存Skip-gram模型skipgram_model.save_model('word2vec_skipgram_model.pth')# 第八部分:模型對比說明print("\n=== 模型對比 ===")print("CBOW和Skip-gram模型訓練完成!")print("- CBOW模型更適合小數據集,訓練速度快")print("- Skip-gram模型更適合大數據集,對罕見詞效果好")# 第九部分:交互式詞向量查詢print("\n=== 交互式詞向量查詢 ===")print("輸入詞匯查看相似詞(輸入'quit'退出):")# 開始交互式查詢循環while True:# 獲取用戶輸入user_input = input("\n請輸入詞匯: ")# 檢查是否退出if user_input.lower() == 'quit':break# 如果輸入非空if user_input.strip():# 使用CBOW模型查找相似詞print(f"\nCBOW模型結果:")similar_cbow = cbow_model.find_similar_words(user_input, top_k=5)# 打印CBOW模型結果if similar_cbow:for word, sim in similar_cbow:print(f" {word}: {sim:.4f}")else:print(" 詞匯不在詞典中")# 使用Skip-gram模型查找相似詞print(f"\nSkip-gram模型結果:")similar_sg = skipgram_model.find_similar_words(user_input, top_k=5)# 打印Skip-gram模型結果if similar_sg:for word, sim in similar_sg:print(f" {word}: {sim:.4f}")else:print(" 詞匯不在詞典中")# 程序入口點
if __name__ == "__main__":# 調用主函數main()

