深度学习---Rnn-文本分类

# 导入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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88409.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20250709解决KickPi的K7开发板rk3576-android14.0-20250217.tar.gz编译之后刷机启动不了

【整体替换】 Z:\20250704\rk3576-android14.0\rkbin清理编译的临时结果&#xff1a; rootrootrootroot-X99-Turbo:~$ cd 14TB/versions/rk3576-android14.0-20250217k7/ rootrootrootroot-X99-Turbo:~/14TB/versions/rk3576-android14.0-20250217k7$ ll rootrootrootroot-X99-…

怎么创建新的vue项目

首先&#xff0c;新建一个文件点文件路径&#xff0c;输入cmd

CIU32L051系列 DMA串口无阻塞性收发的实现

1.CIU32L051 DMA的通道映射由于华大CIU32L051的DMA外设资源有限&#xff0c;DMA只有两个通道可供使用&#xff0c;对应的通道映射图如下&#xff1a;2.UART对应的引脚分布及其复用映射CIU32L051对应的UART对应的引脚映射图如下,这里博主为了各位方便查找&#xff0c;就直接全拿…

飞算 JavaAI 体验:重塑 Java 开发的智能新范式

飞算 JavaAI 体验&#xff1a;重塑 Java 开发的智能新范式引言&#xff1a;正文&#xff1a;一、工程化代码生成&#xff1a;从 "片段拼接" 到 "模块交付"1.1 传统工具的局限与突破1.2 代码质量验证二、智能重构引擎&#xff1a;从 "问题修复" 到…

深入理解JVM的垃圾收集(GC)机制

引言首先我们来介绍垃圾收集的概念&#xff0c;什么是垃圾收集&#xff1f;垃圾收集 &#xff08;Garbage Collection&#xff0c;GC&#xff09;&#xff0c;顾名思义就是释放垃圾占用的空间&#xff0c;防止内存爆掉。有效的使用可以使用的内存&#xff0c;对内存堆中已经死亡…

【笔记】国标-机动车辆及挂车分类

源于&#xff1a;GB/T 15089-2001机动车辆及挂车分类 1.L类&#xff1a;两轮或三轮车辆2.M类&#xff1a;四轮载客车辆3.N类&#xff1a;四轮载货车辆4.O类&#xff1a;挂车5.G类&#xff1a;其他

VLLM部署DeepSeek-LLM-7B-Chat 模型

一、部署环境准备1. 基础环境要求操作系统&#xff1a;Linux&#xff08;推荐欧拉系统、Ubuntu 等&#xff09;Python 版本&#xff1a;3.8 及以上依赖工具&#xff1a;pip、git、curl可选依赖&#xff1a;GPU 环境&#xff1a;NVIDIA GPU&#xff08;支持 CUDA 11.7&#xff0…

翱翔的智慧之翼:Deepoc具身智能如何赋能巡检无人机“读懂”工业现场

翱翔的智慧之翼&#xff1a;Deepoc具身智能如何赋能巡检无人机“读懂”工业现场在百米高的风力发电机叶片顶端&#xff0c;在蜿蜒数十公里的高压输电线旁&#xff0c;在油气管道穿越的崇山峻岭之上&#xff0c;一架四旋翼无人机正精准地悬停着&#xff0c;它的“眼睛”&#xf…

Java大厂面试实录:谢飞机的电商场景技术问答(Spring Cloud、MyBatis、Redis、Kafka、AI等)

Java大厂面试实录&#xff1a;谢飞机的电商场景技术问答&#xff08;Spring Cloud、MyBatis、Redis、Kafka、AI等&#xff09;本文模拟知名互联网大厂Java后端岗位面试流程&#xff0c;以电商业务为主线&#xff0c;由严肃面试官与“水货”程序员谢飞机展开有趣的对话&#xff…

Kotlin基础

前言 Decrement&#xff08;递减&#xff09; → 将一个值减 1 的操作 Predicate&#xff08;谓词&#xff09; → 返回布尔值&#xff08;逻辑值&#xff09;的函数 Reference&#xff08;引用&#xff09; → 允许使用自定义名称与对象交互 Runtime&#xff08;运行时&…

预防DNS 解析器安全威胁

DNS 是互联网的重要基础&#xff0c;例如 Web 访问、email 服务在内的众多网络服务都和 DNS 息息相关&#xff0c;DNS 的安全则直接关系到整个互联网应用能否正常使用。 DNS 解析器的作用是将用户输入的域名转换为对应的 IP 地址&#xff0c;以便计算机能够准确地定位并连接到…

Windows下VScode配置FFmpeg开发环境保姆级教程

相关准备 提前在本地开发环境中配置好mingw64或者msys2开发工具集。 安装VScode软件。 下载Windows版本的FFmpeg相关库 下载地址&#xff1a;https://ffmpeg.org/download.html 下载步骤&#xff1a;如下图。 下载后的文件&#xff1a;包含了可执行文件ffmpeg、ffpl…

Lecture #19 : Multi-Version Concurrency Control

CMU15445课程笔记多版本并发控制 多版本并发控制讲的是Mvcc。 即维护单个逻辑对象的多个物理版本&#xff0c; 这样当一个事务读取某个对象的时候不会阻塞其他事务写入该对象&#xff1b; 反之亦然。 但是Mvcc不保护写写冲突&#xff0c; 对于这种情况&#xff0c; 可能需要其两…

imx6ul Qt运行qml报错This plugin does not support createPlatformOpenGLContext!

imx6ul运行qml的Qt程序报错This plugin does not support createPlatformOpenGLContext!1、开发环境2、问题复现3、解决办法第一种方法第二种方法4、结论1、开发环境 主板&#xff1a;imx6ul Qt版本&#xff1a;5.9.6 文件系统&#xff1a;buildroot 问题描述&#xff1a;现需…

软考中项系统集成第 5 章:软件工程全流程考点拆解,备考逻辑清晰

备考系统集成项目管理工程师的小伙伴们&#xff0c;福利来啦&#xff01;今天开始为大家带来《系统集成项目管理工程师&#xff08;第 3 版&#xff09;》考点的思维导图&#xff0c;今天带来的是第5章。第 5 章聚焦软件工程&#xff0c;涵盖软件工程定义、软件需求、软件设计、…

ICLR 2025 | InterpGN:时间序列分类的透明革命,Shapelet+DNN双引擎驱动!

在Rensselaer理工学院、Stony Brook大学与IBM Research的合作下&#xff0c;本文聚焦于如何在时间序列分类任务中兼顾性能与可解释性。传统深度学习模型虽然准确率高&#xff0c;却常被诟病为“黑盒”&#xff0c;难以赢得如医疗等高风险领域的信任。为此&#xff0c;作者提出了…

使用ENO将您的JSON对象生成HTML显示

ENO 是简单易用&#xff0c;性能卓越&#xff0c;自由灵活开源的 WEB 前端组件&#xff1b;实现 JSON 与 HTML 互操作的 JavaScript 函数库。没有任何其它依赖&#xff0c;足够轻量。 WEBPack NPM 工程安装。 npm install joyzl/eno 然后在JS中引用 import "joyzl/eno…

7.12 卷积 | 最小生成树 prim

lc1900.模拟比赛算出两个指定选手最早和最晚能在第几轮碰到。还是建议dfs捏模拟比赛&#xff0c;找出两个特定选手&#xff08;firstPlayer和secondPlayer&#xff09;最早和最晚相遇的轮次。1. 定义了一个“选手”结构体&#xff0c;包含两个属性a&#xff08;战斗力&#xff…

LVS-NAT模式配置

目录 1、负载调度器配置 配置IP地址 安装ipvsadm 开启路由转发功能 加载ip_vs模块 启动ipvsadm服务 配置负载分配策略 查看验证 2、web节点配置 3、测试 1、负载调度器配置 配置IP地址 增加一块网卡 cd /etc/sysconfig/network-scripts/ cp ifcfg-ens192 ifcfg-ens…

中国银联豪掷1亿采购海光C86架构服务器

近日&#xff0c;中国银联国产服务器采购大单正式敲定&#xff0c;基于海光C86架构的服务器产品中标&#xff0c;项目金额超过1亿元。接下来&#xff0c;C86服务器将用于支撑中国银联的虚拟化、大数据、人工智能、研发测试等技术场景&#xff0c;进一步提升其业务处理能力、用户…