藏语自然语言处理入门 - 4 找相似的句子

句向量与相似度:给一句话找"近义例句"

本节要做的三件小事

  1. sentences.txt 里的每句话变成一个"向量"(一串数字)。
  2. 用"余弦相似度"比较两句话有多像。
  3. 做一个Top-K 例句检索小工具:输入一句,返回最接近的几句。

做完你会得到:

  • embeddings.npy:每句的句向量(后续可复用)。
  • similar_examples.py:给定句子,找 Top-K 相似例句的脚本。
  • sim_results.txt(示例输出):你查过的结果记录。

小贴士:本课需要下载一个多语句向量模型(体积较大)。如果当前环境网络不方便,可先看懂流程与代码,改天在网络好时跑一下。


0. 准备

bash 复制代码
pip install sentence-transformers numpy pandas

模型选择(二选一):

  • 更准sentence-transformers/LaBSE(覆盖语种多,含藏语;体积较大)
  • 更轻 (可临时用):paraphrase-multilingual-MiniLM-L12-v2(更小更快,但对藏语可能略弱)

我会在代码里给出 MODEL_NAME,默认用 LaBSE;你也可以换成 MiniLM 版本试试。


1) 一次性向量化所有句子

把下面保存为 build_embeddings.py,放在和 sentences.txt 同目录下运行。

python 复制代码
# build_embeddings.py
# 功能:读取 sentences.txt -> 计算句向量 -> 保存 embeddings.npy 和 sentences_index.csv

from pathlib import Path
import numpy as np
from sentence_transformers import SentenceTransformer

SENTS_FILE = "sentences.txt"
MODEL_NAME = "sentence-transformers/LaBSE"  # 或 "paraphrase-multilingual-MiniLM-L12-v2"

def normalize(vectors: np.ndarray) -> np.ndarray:
    # L2 归一化,便于用点积近似余弦相似度
    norms = np.linalg.norm(vectors, axis=1, keepdims=True) + 1e-12
    return vectors / norms

def main():
    sents = [s.strip() for s in Path(SENTS_FILE).read_text(encoding="utf-8").splitlines() if s.strip()]
    if not sents:
        raise SystemExit("❌ sentences.txt 为空,请先完成前几课。")

    print(f"📦 加载模型:{MODEL_NAME}")
    model = SentenceTransformer(MODEL_NAME)

    print(f"🔢 计算向量(共 {len(sents)} 句)...")
    emb = model.encode(sents, batch_size=32, convert_to_numpy=True, normalize_embeddings=True)
    # 若你的模型没有自带 normalize_embeddings,可以改为: emb = normalize(emb)

    np.save("embeddings.npy", emb)
    Path("sentences_index.csv").write_text("\n".join(sents), encoding="utf-8")

    print("✅ 已保存:embeddings.npy / sentences_index.csv")

if __name__ == "__main__":
    main()

运行:

bash 复制代码
python build_embeddings.py

输出文件:

  • embeddings.npy:形状约为 [句子数, 向量维度]
  • sentences_index.csv:和向量同序的原始句子。

2) 近义例句检索

把下面保存为 similar_examples.py。它会读取上一步的 embeddings.npysentences_index.csv,然后对你输入的句子做检索。

python 复制代码
# similar_examples.py
# 用法示例:
#   python similar_examples.py --q "ཁྱེད་ལ་བཀྲ་ཤིས།" --k 5
# 输出:Top-K 相似句及相似度

import argparse
import numpy as np
from pathlib import Path
from sentence_transformers import SentenceTransformer, util

MODEL_NAME = "sentence-transformers/LaBSE"  # 或 "paraphrase-multilingual-MiniLM-L12-v2"

def load_corpus():
    sents = [s.strip() for s in Path("sentences_index.csv").read_text(encoding="utf-8").splitlines() if s.strip()]
    emb = np.load("embeddings.npy")
    if len(sents) != emb.shape[0]:
        raise SystemExit("❌ 句子数量与向量行数不一致,请重新构建。")
    return sents, emb

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--q", type=str, required=True, help="查询句子(藏文)")
    parser.add_argument("--k", type=int, default=5, help="返回前K条")
    args = parser.parse_args()

    sents, emb = load_corpus()
    print(f"📦 加载模型:{MODEL_NAME}")
    model = SentenceTransformer(MODEL_NAME)

    # 编码查询句(已做归一化,余弦相似度=点积)
    q_emb = model.encode([args.q], convert_to_numpy=True, normalize_embeddings=True)[0]

    # 相似度(向量点积)并排序
    scores = emb @ q_emb  # shape: [N]
    idx = np.argsort(-scores)[:args.k]

    lines = []
    for rank, i in enumerate(idx, 1):
        lines.append(f"[Top{rank}] score={scores[i]:.4f}\n{sents[i]}\n")

    out = "\n".join(lines)
    Path("sim_results.txt").write_text(out, encoding="utf-8")
    print(out)
    print("✅ 结果已保存:sim_results.txt")

if __name__ == "__main__":
    main()

试运行:

bash 复制代码
python similar_examples.py --q "ཁྱེད་ལ་བཀྲ་ཤིས།" --k 5

你会看到最接近的 5 句(通常是各种问候、祝福类句子)。


3) 代码"人话讲解"

  • 句向量:把一句话翻译成一个"坐标点"(比如 768 维),相似的句子会靠得更近。
  • 归一化 :把向量长度调成 1,这样点积≈余弦相似度,计算更快。
  • 相似度排序:对所有句子算分数,最高的前 K 条就是"近义例句"。
  • 缓存:向量只算一次保存,下次直接用,速度飞起。

4) 自检清单

  • embeddings.npysentences_index.csv 一一对应(行数要相等)。
  • 查询的句子是藏文 Unicode(不是图片/不是转写)。
  • 返回的 Top 结果读起来确实接近(同一话题、同一语气)。

5) 小任务

任务A(必做) :把 similar_examples.py 包一层简单函数,做个**"课堂查询"**:

  • 输入:一个词或短句;
  • 输出:Top 5 相似句;
  • 额外:把相似度 < 0.5 的结果过滤掉(避免"牵强相似")。

任务B(可选):做一个**"去重"**小规则:如果返回的句子同一行在原文里重复多次,只保留一次(可以按句子文本去重)。

任务C(可选) :把 --q 改成从文件读取 (比如 queries.txt 每行一个查询),一次性批量生成结果。


6) 常见小坑(快速排雷)

  • 模型下载太大/太慢?

    先跑小模型 paraphrase-multilingual-MiniLM-L12-v2 验证流程;等网络好再换回 LaBSE 做最终检索。

  • 结果不稳定?

    语料太短时很正常。多加几段同主题的句子,或先回第1--3课把清洗/停用词做好。

  • 中文/英文混在里面?

    句向量是多语的,一般也能"感觉"相似,但这门课我们以藏文主语料为主,更稳。

  • 返回了一些"太像的句子"(几乎重复)?

    检索前先对 sentences.txt 去重;或者在返回阶段做"文本去重"。


7) 本课小结

  • 我们把"句子 → 向量 → 相似度"这一条链路跑通了;
  • 以后你可以把这套向量直接复用到:聚类、主题分组、跨语检索
  • 这一步是"让机器感受语义"的关键基础。
相关推荐
技术小黑2 小时前
NLP学习系列 | 构建词典
人工智能·nlp
audyxiao0012 小时前
NeurIPS 2025论文分享|FedFree:突破知识共享壁垒的异构联邦学习新框架
大数据·人工智能·机器学习·大模型·智能体
stbomei3 小时前
2025 AI 落地图谱:从技术突破到产业重构的变革之路
人工智能·重构
AI数据皮皮侠4 小时前
全国各省市绿色金融指数及原始数据(1990-2022年)
大数据·人工智能·python·深度学习·机器学习·金融
zzywxc7874 小时前
AI行业应用全景:从金融风控到智能制造的落地实践与技术解析
人工智能·深度学习·spring·机器学习·prompt·制造
丁学文武4 小时前
大模型原理与实践:第二章-Transformer架构_第2部分Encoder-Decoder架构
人工智能·深度学习·transformer
liliangcsdn4 小时前
基于ollama运行27b gemma3解决ffmpeg命令生成问题
人工智能·ffmpeg
云雾J视界5 小时前
算法偏见的解药:将敏捷“灵魂”注入AI伦理
人工智能·算法·谷歌·伦理债·算法偏见·高效程序员·ai决策系统
码界奇点5 小时前
京东JoyAgent-JDGenie开源多智能体系统如何重塑AI应用落地新范式
人工智能·ai·智能手机·开源