java实现Word2Vec预训练字符串相似度例子,详细注释,附工程源码

核心代码

package org.example;

import com.huaban.analysis.jieba.JiebaSegmenter;
import org.deeplearning4j.models.embeddings.loader.WordVectorSerializer;
import org.deeplearning4j.models.word2vec.Word2Vec;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) throws IOException {
        // 输入的两个句子
        String input1 = "一寸光阴一寸金,寸金难买寸光阴。";
        String input2 = "光阴似箭";
        // 词向量模型文件路径
        String modelFile = "baike_26g_news_13g_novel_229g.bin";
        // 读取词向量模型文件
        InputStream is = ClassLoader.getSystemResourceAsStream(modelFile);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(Objects.requireNonNull(is), 1024 * 1024);
        Word2Vec word2VecModel = WordVectorSerializer.readBinaryModel(bufferedInputStream, false, true);
        // 计算并输出两个句子的相似度
        System.out.println(sentenceSimilarity(input1, input2, word2VecModel));
    }

    /**
     * 根据文本内容获取对应的词向量列表
     * @param text 文本内容
     * @param model 词向量模型
     * @return 词向量列表
     */
    private static List<INDArray> getWordVectors(String text, Word2Vec model) {
        // 将文本分词
        List<String> words = segmentWords(text.toLowerCase(Locale.getDefault()));
        // 创建一个列表来存储词向量
        List<INDArray> wordVectors = new ArrayList<>(words.size());
        for (String word : words) {
            if (model.hasWord(word)) {
                wordVectors.add(model.getWordVectorMatrix(word));
            } else {
                // 如果单词不在词汇表中,使用默认向量(这里使用零向量)
                int vectorSize = model.getLayerSize(); // 获取词向量的大小
                INDArray defaultVector = Nd4j.zeros(1, vectorSize); // 创建零向量
                wordVectors.add(defaultVector);
            }
        }
        return wordVectors;
    }

    /**
     * 对句子进行分词处理
     * @param sentence 待分词的句子
     * @return 分词后的词语列表
     */
    private static List<String> segmentWords(String sentence) {
        JiebaSegmenter segmenter = new JiebaSegmenter();
        return segmenter.sentenceProcess(sentence).stream()
                .filter(e -> !" ".equals(e) && !e.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 计算两个向量的余弦相似度
     * @param vec1 第一个向量
     * @param vec2 第二个向量
     * @return 余弦相似度值
     */
    private static double cosineSimilarity(INDArray vec1, INDArray vec2) {
        // 计算两个向量的点积
        double dotProduct = vec1.mulRowVector(vec2).sumNumber().doubleValue();
        // 计算两个向量的模长
        double norm1 = vec1.norm2Number().doubleValue();
        double norm2 = vec2.norm2Number().doubleValue();
        // 计算余弦相似度
        return dotProduct / (norm1 * norm2);
    }

    /**
     * 计算两个句子的相似度
     * @param sentence1 第一个句子
     * @param sentence2 第二个句子
     * @param model 词向量模型
     * @return 句子相似度值
     */
    private static double sentenceSimilarity(String sentence1, String sentence2, Word2Vec model) {
        List<INDArray> vectors1 = getWordVectors(sentence1, model);
        List<INDArray> vectors2 = getWordVectors(sentence2, model);
        INDArray avgVector1 = getAverageVector(vectors1, model.getLayerSize());
        INDArray avgVector2 = getAverageVector(vectors2, model.getLayerSize());
        return cosineSimilarity(avgVector1, avgVector2);
    }

    /**
     * 计算一组向量的平均值向量
     * @param vectors 向量列表
     * @param modelSize 向量维度大小
     * @return 平均向量
     */
    private static INDArray getAverageVector(List<INDArray> vectors, int modelSize) {
        INDArray sumVector = Nd4j.zeros(1, modelSize); // 创建一个与第一个向量形状相同的零向量
        for (INDArray vector : vectors) {
            sumVector.addiRowVector(vector); // 使用addi进行原地操作
        }
        INDArray indArray = sumVector.div(vectors.size());
        sumVector.close();
        return indArray; // 将总和除以向量数量以获得平均值
    }
}

依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>java-nlp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.deeplearning4j</groupId>
            <artifactId>deeplearning4j-nlp</artifactId>
            <version>1.0.0-M2.1</version>
        </dependency>
        <dependency>
            <groupId>nz.ac.waikato.cms.weka</groupId>
            <artifactId>weka-stable</artifactId>
            <version>3.8.6</version>
        </dependency>
        <dependency>
            <groupId>com.huaban</groupId>
            <artifactId>jieba-analysis</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.nd4j</groupId>
            <artifactId>nd4j-native-platform</artifactId>
            <version>1.0.0-M2.1</version>
        </dependency>
    </dependencies>

</project>

2.9G预训练文件

image.png

运行结果

image.png

源码可以点击下方下载

源码以及预训练文件我已经分享到网盘了,可以点击下载
源码下载

喜欢请点赞,有问题请在评论区留言

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中实现基于中文语料的word2vec预训练模型中保留非中文字符,可以采用以下两种方式: 1. 使用jieba分词工具,将文本中的中英文混合的词语分开,并将非中文字符作为一个独立的词汇来处理。示例代码如下: ```python import jieba # 加载停用词表 stopwords = [] with open('stopwords.txt') as f: for line in f: stopwords.append(line.strip()) # 分词,并过滤停用词和非中文字符 def tokenize(text): words = jieba.cut(text) words = [word for word in words if word not in stopwords and '\u4e00' <= word <= '\u9fa5'] return words # 读入文本并进行分词 sentences = [] with open('corpus.txt') as f: for line in f: line = line.strip() words = tokenize(line) sentences.append(words) # 训练模型 from gensim.models import Word2Vec model = Word2Vec(sentences, size=100, window=5, min_count=5, workers=4) ``` 2. 使用正则表达式,将非中文字符作为一个独立的词汇来处理。示例代码如下: ```python import re import jieba # 加载停用词表 stopwords = [] with open('stopwords.txt') as f: for line in f: stopwords.append(line.strip()) # 分词,并过滤停用词和非中文字符 def tokenize(text): text = re.sub(r'[^\u4e00-\u9fa5]+', ' ', text) words = jieba.cut(text) words = [word for word in words if word not in stopwords] return words # 读入文本并进行分词 sentences = [] with open('corpus.txt') as f: for line in f: line = line.strip() words = tokenize(line) sentences.append(words) # 训练模型 from gensim.models import Word2Vec model = Word2Vec(sentences, size=100, window=5, min_count=5, workers=4) ``` 其中,`corpus.txt`是待训练的中文语料文件,`stopwords.txt`是停用词表文件,可以自行准备或从网络上下载。在训练过程中,可以根据需要调整`size`、`window`、`min_count`等参数,以便得到更好的词向量表示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值