ngram模型中文语料实验step by step(2)-ngram模型数据结构表示及建立

2024-05-13 06:08

本文主要是介绍ngram模型中文语料实验step by step(2)-ngram模型数据结构表示及建立,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

n元ngram模型本质上就是trie树的结构

,逐层状态转移。在sun拼音中是采用的是逐层按照顺序用vector表示,查找的时候逐层二分查找。sun拼音的建立ngram模型的方法也是以按照字典序排好序的<ngram元组,次数>序列作为输入建立起来的。

利用顺序存储+二分查找应该是最节省空间的了。但是效率要受一定影响。其余的trie树实现包括可以利用map(hash_map更耗费空间一点),sun拼音也有一个基于map的trie树实现,sirlm是利用自己的一个LHash实现的类似。另外利用double array trie对于这种预先已经排好序不需要动态添加删除的情况也比较适合但是空间占用较大。TODO 以后会尝试比较下,目前我也是按照sun拼音的顺序存储实现的。

image

核心数据结构表示

struct Leaf //底层ngram level元素
{WordID id; //词的编号union{FREQ_TYPE freq; //建立的时候需要先统计次数,最后使用的时候只需要下面的概率值
            PR_TYPE pr;};
}
struct Node : Leaf //非底层ngram level元素
{int child;  //指向下一level的首地址PR_TYPE bow; //回退时候需要用到的系数,最底层叶子不需要
}
typedef std::vector<Node> NodeLevel;
typedef std::vector<Leaf> LeafLevel;
/**核心数据结构*/
vector<NodeLevel > m_nodeLevel; ///非底层 0root, 1gram- (n-1) gram
LeafLevel m_leafLevel; ///底层对应的ngram
为了节约内存空间,sun拼音的这种表示方法区别了底层的节点和上层节点,带来的麻烦是代码稍微烦了一点因为要区别处理了。
例如对于3元模型,m_nodeLevel[0]表示root m_nodeLevel[1], m_nodeLevel[2]表示第一二层,m_leafLevel表示第3层即底层。
注意这个模型是可以改进加速的,sunpinyin用了线索化的方法,P(ABC) P(BCD)那么P(ABC)到C的时候直接转移到P(B)省掉了去level1二分查找的过程,
其实吧我觉得一个简单的方法是直接把level1的存储改为大的vector然后直接按照id,下标索引O(1)访问即可了,因为level1占内存不多而其二分查找最耗时。
更好的优化以后再考虑吧,这个模型基本够用了,我用这样一个模型存储的占内存260M的ngram信息,进行简单的3元模型概率分词也能达到4-5/M每秒的速度。

ngram模型的建立算法

   /**
     * 初始化构建n gram模型的资源
     */void init(int n){//-------设置n元模型m_nLevel = n;//-------初始化核心数据结构空间m_nodeLevel.resize(n);for (size_t i = 1; i < n; i++){m_nodeLevel[i].reserve(kMemInitAllocSize);}m_leafLevel.reserve(kMemInitAllocSize);//        m_level.resize(n + 1, NULL);//添加根节点m_nodeLevel[0].push_back(Node(0, 0, 0));//-------初始化nr 二维数组m_nr.resize(n + 1);for (size_t i = 0; i < n + 1; i++){m_nr[i].resize(kNGramMaxCutR, 0);}//-------初始化剪枝数组m_cut.resize(n + 1, 0);}
 /**
     * 注意是按照word id字典排序输入的
     * 如果ngram[i] (0<i<=n-1) 为排除在外的词,则只统计ngram[0..i-1]的出现次数;
     * 如果ngram[i] (0<=i<=n-1) 为句子分割词的ID(我们在参数中指定为10),则只统计ngram[0..i]的出现次数。
     * 如果某个trigram为(9, x, y),则直接就跳过了;
     * 如果是(x, 9, y),则只统计unigram (x);如果是(10, x, y),则统计unigram (10),bigram(10,x),trigram(10,x,y);
     * 如果是(x, 10, y),则统计unigram(x)和bigram (x, 10)。
     */void addNGram(const WordID* ngram, FREQ_TYPE fr){int ch;bool brk = isExcludeID(*ngram);//如果是需要忽略的位置,特别是指标明岐义的位置,则不统计任何信息 (9,x,y)否则统计一元信息先if (!brk){m_nodeLevel[0][0].freq += fr; //统计1gram的总数目 对应0gram}elsereturn;//如果需要先手工增大空间reallocMem();bool branch = false;//i = 1 第1个level 对应 ngram[i - 1]即  ngram[0] 要求ngram[0]不是exclude id 9//如果ngram <100,200,300> 是按顺序 –> <100> <100,200><100,200,300>for (int i = 1; (!brk && i < m_nLevel); i++){NodeLevel & pv = m_nodeLevel[i - 1];NodeLevel & v = m_nodeLevel[i];//1.如果前面出现新状态则后面必定都是新状态  branch = branch ||     // 1,2,3 | 2,2,3 对于<2,2>来说这是一个新的状态需要push_back因为上一个level已经发现时新状态了//2.第一次addNGram且i==1时判断用  branch = (pv.back().child >= v.size()) ||//3.如果当前的 id变化了则必然是新状态 branch = (v.back().id != ngram[i - 1]) || // 1, 2, 3| 1, 4, 3对于 <1,4>来说是一个新状态因为本level中由 2 ->4// 另外举例:1 2 3, 1 2 4, 2 2 4, 2 4 4  注意level 2 的 第3个 2是一个新的level 2的状态 而第2个2不是!branch = branch || (pv.back().child >= v.size()) || (v.back().id != ngram[i - 1]);if (branch){if (i == m_nLevel - 1)ch = m_leafLevel.size();elsech = m_nodeLevel[i + 1].size();v.push_back(Node(ngram[i - 1], ch, fr));}else{v.back().freq += fr;}brk = (i > 1 && isBreakID(ngram[i - 1])) || isExcludeID(ngram[i]); //判断下一个 i+1 level对应的ngram[i]是否有效, 注意开头是break id的所有unigram,bigram,trigram都还要统计}//n元组加入到叶子levelif (!brk){if (fr > m_cut[m_nLevel]){m_leafLevel.push_back(Leaf(ngram[m_nLevel - 1], fr));}else //尽管没有添加次数少被剪掉的节点但是仍然统计其次数{m_nr[m_nLevel][0] += fr;m_nr[m_nLevel][fr] += fr;}}}

这样我们就建立好了ngram模型了,注意最后需要添加tail方便二分查找。比如再第一层的状态A位置迭代器为iter,则查找A->C状态 即第二层中对应前面是A当前状态是C的状态,只需要在m_nodeLevel[2]的下标为[iter->child,(iter + 1)->child)的范围内查找。

ngram简单频率模型和概率模型测试结果:

pr对应相对概率P(END|AB..) pr2对应绝对概率P(AB…END),如果概率为0标示为-1。这是一个完全按照最大似然概率的简单ngram模型,没有任何光滑,这会造成很多无概率情况出现,后面会继续介绍模型的光滑方法。

testNgram/test_freq.input
line ------- 美丽 的 一天
freq ------- 0
line ------- 最 伟大 的
freq ------- 0
line ------- 小红 读 了
freq ------- 1
line ------- 小明 读 了
freq ------- 1
line ------- 了 一本 书
freq ------- 0
line ------- b 美丽 的
freq ------- 3
line ------- 美丽 的
freq ------- 3
line ------- 美丽 的 世界
freq ------- 1
line ------- 美丽 的 心灵
freq ------- 2
line ------- 美丽
freq ------- 3
line ------- 本书 b
freq ------- 2
line ------- 本书
freq ------- 2
line ------- 一 本书 b
freq ------- 2
line ------- 的 心灵 b
freq ------- 2
line ------- b 小明 读
freq ------- 1
line ------- b b b
freq ------- 0
line ------- b b
freq ------- 0
line ------- b
freq ------- 11  //注意break id 10出现的次数统计为11,这里每个句子的结束和下一个句子的开始算作1个break id,另外最后一个句子的结束不统计,最终break id的个数其实=start pos的个数
i ------- 2
i ------- 1
i ------- 0
line ------- 美丽 的 一天
pr ------- -1
pr2 ------- -1
line ------- 最 伟大 的
pr ------- -1
pr2 ------- -1
line ------- 小红 读 了
pr ------- 1
pr2 ------- 0.025
line ------- 小明 读 了
pr ------- 1
pr2 ------- 0.025
line ------- 了 一本 书
pr ------- -1
pr2 ------- -1
line ------- b 美丽 的
pr ------- 1
pr2 ------- 0.075
line ------- 美丽 的
pr ------- 1
pr2 ------- 0.075
line ------- 美丽 的 世界
pr ------- 0.333333
pr2 ------- 0.025
line ------- 美丽 的 心灵
pr ------- 0.666667
pr2 ------- 0.05
line ------- 美丽
pr ------- 0.075
pr2 ------- 0.075
line ------- 本书 b
pr ------- 1
pr2 ------- 0.05
line ------- 本书
pr ------- 0.05
pr2 ------- 0.05
line ------- 一 本书 b
pr ------- 1
pr2 ------- 0.05
line ------- 的 心灵 b
pr ------- 1
pr2 ------- 0.05
line ------- b 小明 读
pr ------- 1
pr2 ------- 0.025
line ------- b b b
pr ------- -1
pr2 ------- -1
line ------- b b
pr ------- -1
pr2 ------- -1
line ------- b
pr ------- 0.275
pr2 ------- 0.275

这篇关于ngram模型中文语料实验step by step(2)-ngram模型数据结构表示及建立的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/984887

相关文章

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

Spring AI Alibaba接入大模型时的依赖问题小结

《SpringAIAlibaba接入大模型时的依赖问题小结》文章介绍了如何在pom.xml文件中配置SpringAIAlibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓... 目录(一)pom.XML文件:(二)application.yml配置文件(一)pom.xml文件:首

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Java下载文件中文文件名乱码的解决方案(文件名包含很多%)

《Java下载文件中文文件名乱码的解决方案(文件名包含很多%)》Java下载文件时,文件名中文乱码问题通常是由于编码不正确导致的,使用`URLEncoder.encode(filepath,UTF-8... 目录Java下载文件中文文件名乱码问题一般情况下,大家都是这样为了解决这个问题最终解决总结Java下

如何在本地部署 DeepSeek Janus Pro 文生图大模型

《如何在本地部署DeepSeekJanusPro文生图大模型》DeepSeekJanusPro模型在本地成功部署,支持图片理解和文生图功能,通过Gradio界面进行交互,展示了其强大的多模态处... 目录什么是 Janus Pro1. 安装 conda2. 创建 python 虚拟环境3. 克隆 janus

本地私有化部署DeepSeek模型的详细教程

《本地私有化部署DeepSeek模型的详细教程》DeepSeek模型是一种强大的语言模型,本地私有化部署可以让用户在自己的环境中安全、高效地使用该模型,避免数据传输到外部带来的安全风险,同时也能根据自... 目录一、引言二、环境准备(一)硬件要求(二)软件要求(三)创建虚拟环境三、安装依赖库四、获取 Dee

DeepSeek模型本地部署的详细教程

《DeepSeek模型本地部署的详细教程》DeepSeek作为一款开源且性能强大的大语言模型,提供了灵活的本地部署方案,让用户能够在本地环境中高效运行模型,同时保护数据隐私,在本地成功部署DeepSe... 目录一、环境准备(一)硬件需求(二)软件依赖二、安装Ollama三、下载并部署DeepSeek模型选

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英