从零开始用bert-base-chinese做特征提取:768维中文词向量生成教程
1. 教程简介
你想过让计算机真正"理解"中文词语的含义吗?传统方法只能处理表面文字,而BERT模型能让每个中文词语都拥有一个768维的"数字身份证",这个身份证能精准表达词语的深层语义。
本教程将手把手教你使用bert-base-chinese模型,从零开始生成高质量的中文词向量。无需深厚的技术背景,只要跟着步骤操作,你就能在10分钟内看到第一个中文词语的768维向量表达。
学习目标:
- 理解BERT特征提取的基本原理
- 掌握使用bert-base-chinese生成词向量的完整流程
- 学会将生成的向量应用到实际项目中
前置要求:
- 基本的Python语法知识
- 会使用命令行终端
- 无需机器学习背景(我们会用最直白的语言解释)
2. 环境准备与快速启动
2.1 镜像环境说明
本教程基于预配置的bert-base-chinese镜像环境,已经为你准备好了所有依赖:
- Python版本:3.8+(已安装)
- 深度学习框架:PyTorch(已安装)
- 模型库:Hugging Face Transformers(已安装)
- 模型文件:bert-base-chinese全套权重(已下载)
这意味着你不需要自己安装任何软件或下载模型,省去了最麻烦的环境配置步骤。
2.2 一分钟快速启动
打开终端,输入以下命令即可开始:
# 进入模型目录 cd /root/bert-base-chinese # 运行演示脚本 python test.py运行后你会立即看到三个功能演示:
- 完型填空:模型自动补全句子中的缺失词语
- 语义相似度:计算两个句子的相似程度
- 特征提取:展示词语的768维向量(这是我们重点要学的)
3. BERT特征提取原理解析
3.1 什么是词向量?
简单来说,词向量就是把文字转换成数字的方法。但BERT的厉害之处在于,它生成的数字不是随机的,而是能准确表达词语含义的。
比如:
- "苹果"和"香蕉"都是水果,它们的向量在数字空间里会很接近
- "苹果"和"公司"虽然字一样但意思不同,它们的向量就会相距较远
3.2 BERT为什么特别?
传统的词向量是"静态"的——每个词语无论上下文都只有一个固定向量。而BERT是"动态"的——同一个词语在不同句子中会有不同的向量表达。
举个例子:
- "银行"在"我去银行存钱"和"河岸边的银行"中意思不同
- BERT会为这两种情况生成不同的向量,准确反映语境差异
3.3 768维向量的含义
BERT生成的每个向量有768个数字,这些数字不是乱码,而是代表了词语在不同语义维度上的特征:
- 前几十维可能编码词性(名词、动词等)
- 中间维度可能编码情感(正面、负面)
- 后面维度可能编码领域(科技、医疗、金融等)
这些维度是模型自动学习得到的,不需要人工定义。
4. 实战:生成你的第一个词向量
4.1 基础代码框架
让我们从最简单的代码开始,生成"人工智能"这个词的向量:
from transformers import BertTokenizer, BertModel import torch # 加载预训练模型和分词器 tokenizer = BertTokenizer.from_pretrained('/root/bert-base-chinese') model = BertModel.from_pretrained('/root/bert-base-chinese') # 准备输入文本 text = "人工智能" inputs = tokenizer(text, return_tensors="pt") # 获取模型输出 with torch.no_grad(): outputs = model(**inputs) # 提取词向量(最后一层隐藏状态) word_vectors = outputs.last_hidden_state print(f"向量形状: {word_vectors.shape}")运行这段代码,你会看到输出:向量形状: torch.Size([1, 4, 768])
这表示:
1:批处理大小(我们只输入了一个句子)4:token数量(包括特殊符号)768:每个token的向量维度
4.2 提取纯净词向量
上面的输出包含了特殊符号,我们通常只需要词语本身的向量:
# 提取第一个实际词语的向量(去掉[CLS]和[SEP]) actual_word_vector = word_vectors[0, 1, :] # 取第一个句子的第二个token print(f"纯净词向量形状: {actual_word_vector.shape}") print(f"前10个维度值: {actual_word_vector[:10]}")现在你得到了"人工智能"这个词语的纯净768维向量!
5. 处理完整句子的技巧
5.1 获取句子中每个词的向量
实际应用中,我们通常需要处理整个句子:
def get_sentence_vectors(sentence): # 编码句子 inputs = tokenizer(sentence, return_tensors="pt", padding=True, truncation=True) # 获取模型输出 with torch.no_grad(): outputs = model(**inputs) # 提取所有token的向量 all_vectors = outputs.last_hidden_state # 获取实际词语的索引(去掉特殊符号) token_ids = inputs['input_ids'][0] word_tokens = [tokenizer.convert_ids_to_tokens(token_id) for token_id in token_ids] # 过滤出实际词语的向量 word_vectors = [] for i, token in enumerate(word_tokens): if token not in ['[CLS]', '[SEP]', '[PAD]']: word_vectors.append(all_vectors[0, i, :]) return word_vectors # 测试 sentence = "自然语言处理很有趣" vectors = get_sentence_vectors(sentence) print(f"句子包含 {len(vectors)} 个词语") print(f"每个词语向量维度: {vectors[0].shape}")5.2 处理长文本的策略
BERT有512个token的长度限制,处理长文本时需要分段:
def process_long_text(long_text, max_length=510): # 留两个位置给[CLS]和[SEP] # 分段处理 segments = [] words = long_text.split() current_segment = [] current_length = 0 for word in words: # 估算token数量(中文通常一个字一个token) word_length = len(word) if current_length + word_length > max_length: segments.append(" ".join(current_segment)) current_segment = [word] current_length = word_length else: current_segment.append(word) current_length += word_length if current_segment: segments.append(" ".join(current_segment)) # 分别处理每个段落 all_vectors = [] for segment in segments: segment_vectors = get_sentence_vectors(segment) all_vectors.extend(segment_vectors) return all_vectors6. 实际应用案例
6.1 词语相似度计算
有了词向量,我们可以计算任意两个词语的相似度:
import torch.nn.functional as F def calculate_similarity(word1, word2): # 获取两个词的向量 vec1 = get_sentence_vectors(word1)[0] vec2 = get_sentence_vectors(word2)[0] # 计算余弦相似度 cosine_sim = F.cosine_similarity(vec1.unsqueeze(0), vec2.unsqueeze(0)) return cosine_sim.item() # 测试相似度 similarity = calculate_similarity("苹果", "香蕉") print(f"苹果和香蕉的相似度: {similarity:.4f}") similarity2 = calculate_similarity("苹果", "电脑") print(f"苹果和电脑的相似度: {similarity2:.4f}")你会发现水果之间的相似度远高于水果和电子产品之间的相似度。
6.2 文本分类特征提取
BERT向量是完美的机器学习特征,可以用在各种分类任务中:
def extract_text_features(texts): """为多个文本提取特征向量""" all_features = [] for text in texts: # 获取句子中所有词的向量 word_vectors = get_sentence_vectors(text) # 平均池化得到文本整体向量 if word_vectors: text_vector = torch.mean(torch.stack(word_vectors), dim=0) all_features.append(text_vector.numpy()) else: all_features.append(np.zeros(768)) return np.array(all_features) # 示例:情感分析特征提取 positive_texts = ["这部电影很好看", "音乐非常动人", "表演很精彩"] negative_texts = ["太糟糕了", "浪费时间", "完全不推荐"] # 提取特征 positive_features = extract_text_features(positive_texts) negative_features = extract_text_features(negative_texts) print(f"正面文本特征形状: {positive_features.shape}") print(f"负面文本特征形状: {negative_features.shape}")这些特征可以直接用于训练分类器,效果通常比传统方法好很多。
7. 高级技巧与优化
7.1 使用不同层的向量
BERT有12层 transformer 层,每层捕获的信息不同:
def get_layer_vectors(sentence, layer_number=-1): """获取特定层的词向量""" inputs = tokenizer(sentence, return_tensors="pt") # 获取所有层的输出 with torch.no_grad(): outputs = model(**inputs, output_hidden_states=True) # 选择特定层(-1表示最后一层) layer_vectors = outputs.hidden_states[layer_number] return layer_vectors # 比较不同层的效果 last_layer = get_layer_vectors("深度学习") # 最后一层,语义信息丰富 first_layer = get_layer_vectors("深度学习", layer_number=0) # 第一层,语法信息更多经验法则:
- 最后几层:适合语义相关任务(相似度、分类)
- 中间层:平衡语法和语义信息
- 第一层:更适合语法分析任务
7.2 批量处理提高效率
处理大量文本时,批量处理可以大幅提升速度:
def batch_process_texts(texts, batch_size=32): """批量处理文本""" all_vectors = [] for i in range(0, len(texts), batch_size): batch_texts = texts[i:i+batch_size] # 批量编码 inputs = tokenizer(batch_texts, return_tensors="pt", padding=True, truncation=True, max_length=128) with torch.no_grad(): outputs = model(**inputs) # 处理每个文本的向量 for j in range(len(batch_texts)): # 获取实际token的向量(去掉特殊符号) attention_mask = inputs['attention_mask'][j] vectors = outputs.last_hidden_state[j] actual_vectors = vectors[attention_mask.bool()][1:-1] # 去掉[CLS]和[SEP] # 平均池化得到文本向量 if len(actual_vectors) > 0: text_vector = torch.mean(actual_vectors, dim=0) all_vectors.append(text_vector.numpy()) else: all_vectors.append(np.zeros(768)) return np.array(all_vectors)8. 常见问题解决
8.1 内存不足怎么办?
处理长文本时可能遇到内存问题:
# 解决方案1:使用更小的批次 vectors = batch_process_texts(texts, batch_size=8) # 减小batch_size # 解决方案2:使用梯度检查点(节省内存但稍慢) model = BertModel.from_pretrained('/root/bert-base-chinese', use_gradient_checkpointing=True) # 解决方案3:使用半精度浮点数 model = model.half() # 使用FP16减少内存占用8.2 处理速度太慢?
# 启用CUDA加速(如果有GPU) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = model.to(device) # 推理时使用no_grad()和eval()模式 model.eval() with torch.no_grad(): outputs = model(**inputs) # 预先加载模型,避免重复加载 # 在程序开始时加载一次,后续直接使用8.3 特殊字符和未登录词
BERT使用WordPiece分词,能很好处理未登录词:
# 即使是不常见的词语,BERT也能处理 rare_word = "量子计算" vectors = get_sentence_vectors(rare_word) print(f"'{rare_word}'的向量已成功生成") # 处理特殊字符 special_text = "Python3.8+ & TensorFlow2.x" vectors = get_sentence_vectors(special_text) print(f"特殊文本处理完成,生成{len(vectors)}个词向量")9. 总结
通过本教程,你已经掌握了使用bert-base-chinese生成768维中文词向量的完整技能。让我们回顾一下重点:
核心收获:
- 环境配置简单:使用预配置镜像,省去复杂的环境搭建
- 基础使用容易:几行代码就能生成高质量词向量
- 应用场景丰富:从词语相似度计算到文本分类都能应用
- 进阶技巧实用:批量处理、分层提取等技巧提升效率和质量
下一步学习建议:
- 尝试将生成的向量用于你的具体项目
- 探索不同层向量的效果差异
- 学习如何微调BERT模型适应特定领域
- 了解其他预训练模型(如ERNIE、RoBERTa等)的特点
实践是最好的学习——现在就开始用BERT向量增强你的NLP项目吧!你会发现,原本复杂的中文语义理解任务,因为有了768维的"数字身份证"而变得简单而强大。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。