作业9.2:论文查重

这个作业属于哪个课程 班级链接
这个作业要求在哪里 作业要求链接
这个作业的目标 设计论文查重算法;学会 Git 版本控制。

Github 链接:博客正文首行 github 链接

目录
  • 一、整体设计
    • 开发环境
    • 整体设计
    • 项目结构
  • 二、模块接口的设计与实现
    • 核心的类与方法
    • 类与函数的调用关系
    • 核心算法
  • 三、接口部分性能改进
    • 性能分析图
    • 性能统计数据
    • 性能改进
  • 四、单元测试
    • 单元测试概览
    • 测试函数的设计
      • 测试函数的说明与构造思路
      • 测试代码
    • 测试覆盖率截图
  • 五、异常处理
    • 异常处理设计
      • 1. AttributeError
        • 设计目标
        • 单元测试样例
        • 错误对应场景
      • 2. ZeroDivisionError
        • 设计目标
        • 单元测试样例
        • 错误对应场景
      • 3. AssertionError
        • 设计目标
        • 单元测试样例
        • 错误对应场景
  • 六、PSP表格

一、整体设计

开发环境

  • 编程语言:python 3
  • IDE:PyCharm 2024.2.1 (Professional Edition)

整体设计

项目结构

.
├── .idea
├── 3121005661
├── src	                            // 存放测试类
│   ├── get_tokenize.py	            // 数据预处理模块
│   ├── google_bleu.py		    // BLEU 模块
│   └── rouge.py		    // ROUGE 模块
├── test		            // 存放测试类
│   ├── test_bleu.py		    // 测试函数:BLEU
│   ├── test_generate_string.py	    // 测试函数:词元化
│   ├── test_generate_vocab.py	    // 测试函数:生成词表
│   ├── test_index_token.py	    // 测试函数:token 序列化
│   ├── test_leven_sim.py	    // 测试函数:编辑距离
│   └── test_rouge.py		    // 测试函数:Rouge
├── readme.md			    // Github readme 文档
├── call_graph.py		    // 打印程序调用关系图
└── main.py			    // 程序入口

二、模块接口的设计与实现

核心的类与方法

  • main_process方法:算法的主程序,将全流程调用的各种方法串联起来
  • levenshtein_similarity方法:计算编辑距离的算法
  • eval_accuracies方法:计算精确相似度的程序,调用方法计算bleu得分和rouge得分
  • Rouge类:计算rouge得分的算法
  • compute_bleu方法:计算bleu得分的算法

类与函数的调用关系

下图为程序的调用关系图,该图由pycallgraph库通过运行代码自动生成。图中,灰色标注的方块是系统内部的函数,彩色标注的方块是我自己编写的函数。由图可见,程序开始执行时,首先调用main_process函数,该函数调用get_tokenize.py文件的方法,对输入的文本进行预处理,然后调用eval_accuracies函数进行评估,该函数又调用了google_bleu.pyrouge.py文件的具体方法。

核心算法

本程序的一个核心算法是BLEU算法

算法关键:n-gram准确率的计算。n-gram是指n个连续单词组成的单元,称为n元语法。如果采用1-gram匹配,如果每个文本一共6个词,有5个词语都相同,那么它1-gram的匹配度为 5/6。如果每个文本一共可以分为四个3-gram的词组,其中有两个可以命中参考译文,那么它3-gram的匹配度为 2/4。

独到之处:

  • 在本算法中,对于参考句子和改编句子的token,我首先取得他们各自的n-gram语法的token序列,用字典存储。然后,通过对两个字典取交集,可以很方便地得到两个token序列中匹配的部分。
  • 在本算法中,求低元语法可以在求高元语法的基础上进行,避免了重复运算。例如,在4-gram语法的token序列后,我通过遍历每个token,就能获得3-gram语法、2-gram语法、1-gram语法的token序列,从而既能求得4-gram准确率,又能求得3-gram2-gram1-gram准确率,而不需要重头开始计算他们。

三、接口部分性能改进

性能分析图

如上图所示,我使用pycharm专业版的profile工具,通过程序性能分析图展现各个模块的大致性能情况,红色代表耗时最大,橙色代表耗时较大,绿色代表耗时较小。通过上图观察发现,除了耗时最大的主程序mainmain process,一个核心的自定义方法get_vocab也是耗时较多的,是需要重点改进、优化的对象。

为了验证上述说法,我们通过profile工具的性能统计数据来进一步了解程序各部分的详细耗时数据。

性能统计数据

如上表所示,展示了程序执行过程中用到了各种方法和耗时情况,其中包括自定义方法和一些内部方法。如果按照Call Count进行调用次数的从大到小排序,发现大多都是系统类型的调用,其中调用最多的是一个核心的内部方法max,一共调用了 94150 次。通过这种方式无法找出性能优化的方向。

如上表所示,如果按照Time进行耗时的从大到小排序,可以发现,除了核心主程序mainmain process,一个核心的自定义方法get_vocab是所有自定义方法中耗时最多的,而这一方法只是用于对token建立词汇表,进一步验证了这个方法其实是需要改进或者是需要被优化的。

性能改进

基于上面的问题,我们对算法进行调整,对于输入的两个文本,我们直接使用轻量级的编辑距离计算相似度,如果相似度低于 50% ,为了确保查重的准确率,我们才调用自定义方法get_vocab、使用BLEU算法进行计算。性能优化后的情况如下:

可以看到主程序main的总用时变为 145 ms,相较于之前快了 667 ms,一般情况下的性能有所提高。

四、单元测试

单元测试概览

测试功能 测试文件 测试等价类1 测试等价类2 测试等价类3 测试覆盖率
BLEU计算 test_bleu.py 输入均为空字典 输入数据不匹配 合法正例 61%
字符串生成 test_generate_string.py 输入为空字符串 输入错误数据类型 合法正例 57%
词表生成 test_generate_vocab.py 输入为空 输入错误数据类型 合法正例 57%
词元序列化 test_index_token.py 输入为空列表 特殊边界情况:UNK 合法正例 55%
编辑距离计算 test_leven_sim.py 输入为空字符串 输入错误数据类型 合法正例 50%
ROUGE计算 test_rouge.py 输入均为空字典 输入数据不匹配 合法正例 58%

测试函数的设计

由于测试函数和测试类过多,下面仅以BLEU计算的测试函数为例,介绍测试函数的设计,其余测试大同小异。

对于BLEU计算模块,他的基本特点如下:

特征 说明
函数功能 使用n-gram算法计算两段文本的BLEU相似度
输入 两个序列,分别代表两段文本
输入的数据类型 均为字典,其中他们的键必须相同,值必须为单字符串列表
输出 文本的BLEU相似度、每个句子的BLEU平均得分、BLEU得分字典

针对BLEU计算模块的基本特点,在下面的代码块中,我们设计了 5 个测试函数,囊括了 3 个基本等价类,从而能够对输入为空的情况、输入数据类型、正例进行严密的测试。当然,这次作业的目的是熟悉工具的使用,因此并不会对测试的完整性、异常情况处理等进行很仔细的讨论和实施,实际的开发过程应该要比当前情况严谨的多

测试函数的说明与构造思路

  • test_corpus_bleu_empty:该测试函数测试输入数据为空的情况,旨在测试原函数的输入检验模块。当函数的输入为空,意味着比较的文本是不存在的,在BLEU计算中会出现除数为 0 的情况。这是程序中的异常情况,因此应当采用assertRaises输出提示信息,并且抛出异常。
  • test_corpus_bleu_ID_incorrect:该测试函数测试输入数据类型错误的情况。当函数的输入不是字典,意味着预处理后的数据存在问题,而这个问题可能与当前模块无关。这是程序中的异常情况,因此应当采用assertRaises输出提示信息,并且抛出异常。
  • test_corpus_bleu_right:测试正例。当两个的输入完全一致,意味着文本的相似度为 100%,程序应输出相似度1。
  • test_corpus_bleu_ID_incorrect2:该测试函数测试输入数据存在键值对错误的情况,旨在测试原函数的输入检验模块。当函数的输入存在多个 hypothesis 和 reference 的 ID 相同,即键的数量不匹配,某个输入多了或者少了,意味着预处理后的数据存在问题,而这个问题可能与当前模块无关。这是程序中的异常情况,因此应当采用assertRaises输出提示信息,并且抛出异常。
  • test_corpus_bleu_hyp_list_incorrect:该测试函数测试输入数据类型错误的情况,对第二个测试函数进行补充。

测试代码

import unittest
import sys
sys.path.append('..')
from src.google_bleu import corpus_bleu, compute_bleuclass TestGetVocab(unittest.TestCase):def test_corpus_bleu_empty(self):"""空"""hypothesis = {}references = {}self.assertRaises(ZeroDivisionError, corpus_bleu, hypothesis, references)def test_corpus_bleu_ID_incorrect(self):"""数据类型错误"""hypothesis = {'id1': ['This is a test.'],'id2': ['This is another test.']}references = {'id3': ['This is a test.'],'id4': ['This is another test.']}self.assertRaises(AssertionError, corpus_bleu, hypothesis, references)def test_corpus_bleu_right(self):"""正例"""hypothesis = {'id1': ['This is a test.'],'id2': ['This is another test.']}references = {'id1': ['This is a test.'],'id2': ['This is another test.']}bleu, avg_score, ind_score = corpus_bleu(hypothesis, references)self.assertEqual(bleu, 1.0)self.assertEqual(avg_score, 1.0)self.assertEqual(ind_score, {'id1': 1.0, 'id2': 1.0})def test_corpus_bleu_ID_incorrect2(self):"""存在多个 hypothesis 和 reference 的 ID 相同"""hypothesis = {'id1': ['This is a test.'],'id2': ['This is another test.']}references = {'id1': ['This is a test.'],'id2': ['This is another test.'],'id3': ['This is a different test.']}self.assertRaises(AssertionError, corpus_bleu, hypothesis, references)def test_corpus_bleu_hyp_list_incorrect(self):"""hypothesis 和 reference 的 数量不匹配"""hypothesis = {'id1': ['This is a test.'],'id2': ['This is another test.']}references = {'id1': ['This is a test.'],'id2': ['This is another test.']}hyp_list = [hypothesis['id1']]ref_list = [references['id1'], references['id2']]self.assertRaises(AttributeError, corpus_bleu, hyp_list, ref_list)

测试覆盖率截图








五、异常处理

异常处理设计

对于程序中可能出现的异常,我们为了保证程序的继续执行,往往将异常抛出的同时执行一系列的异常处理代码。对于作业,相对来说不需要太严谨,因此我这里只将异常抛出即可。因为异常处理涉及的模块较多,这里以以BLEU计算模块为例,介绍设计思路

1. AttributeError

设计目标

当输入错误的数据类型,将报错信息引出,同时让用户修改数据类型或者将当前数据改为正确类型的数据。

单元测试样例
    def test_corpus_bleu_ID_incorrect(self):"""数据类型错误"""hypothesis = {'id1': 'This is a test.','id2': ['This is another test.']}references = {'id3': ['This is a test.'],'id4': ['This is another test.']}self.assertRaises(AssertionError, corpus_bleu, hypothesis, references)
错误对应场景

输入的数据中存在不是字典的数据。当输入错误的数据类型,原程序执行到Ids = list(hypotheses.keys())这一句,程序会引发AttributeError异常,我们拿到这样的数据,说明前面的代码存在问题,因此我们将报错信息引出,同时让用户修改数据类型或者将当前数据改为正确类型的数据。

2. ZeroDivisionError

设计目标

当输入为空,将报错信息引出,同时让用户重新输入

单元测试样例
    def test_corpus_bleu_ID_incorrect(self):"""数据类型错误"""hypothesis = {'id1': 'This is a test.','id2': ['This is another test.']}references = {'id3': ['This is a test.'],'id4': ['This is another test.']}self.assertRaises(AssertionError, corpus_bleu, hypothesis, references)
错误对应场景

当输入为空,除法的除数变成 0 ,引发异常。说明前面的代码存在问题,因此我们将报错信息引出,同时让用户重新输入

3. AssertionError

设计目标

当输入的数据键值对不匹配,将报错信息引出,同时让用户检查输入

单元测试样例
    def test_corpus_bleu_ID_incorrect2(self):"""存在多个 hypothesis 和 reference 的 ID 相同"""hypothesis = {'id1': ['This is a test.'],'id2': ['This is another test.']}references = {'id1': ['This is a test.'],'id2': ['This is another test.'],'id3': ['This is a different test.']}self.assertRaises(AssertionError, corpus_bleu, hypothesis, references)
错误对应场景

当输入的数据键值对不匹配,会引发AssertionError异常,我们拿到这样的数据,首先输出错误信息,然后让用户检查输入。

六、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 8
· Estimate · 估计这个任务需要多少时间 15 8
Development 开发 190 201
· Analysis · 需求分析 (包括学习新技术) 30 14
· Design Spec · 生成设计文档 20 12
· Design Review · 设计复审 10 6
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 18
· Design · 具体设计 20 14
· Coding · 具体编码 40 63
· Code Review · 代码复审 20 12
· Test · 测试(自我测试,修改代码,提交修改) 40 62
Reporting 报告 160 138
· Test Repor · 测试报告 60 121
· Size Measurement · 计算工作量 10 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 90 12
合计 365 347

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

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

相关文章

搭建企业内部的大语言模型系统

大纲开源大语言模型 大语言模型管理 私有大语言模型服务部署方案开源大语言模型 担心安全与隐私?可私有部署的开源大模型商业大模型,不支持私有部署ChatGPT Claude Google Gemini 百度问心一言开源大模型,支持私有部署Mistral Meta Llama ChatGLM 阿里通义千问常用开源大模型…

115. 不同的子序列(leetcode)

https://leetcode.cn/problems/distinct-subsequences/submissions/563375885/ 这题比较有难度,具体不太好想到,需要以是否选择s[i]来划分子集这位描述的很清楚,不做过多赘述 class Solution {public int numDistinct(String s, String t) {// f[i][j]表示s中前i个字符中选择,有…

0.1+0.2 != 0.3 (Java为例)

1. 小数的二进制表示 以10.625为例。整数部分进行除2取余的操作,10的二进制为1010。小数部分进行乘2取整操作,直到小数部分为0或达到需要的精度:0.625*2=1.25 取整数1,小数部分0.25继续计算 0.25*2=0.5 取整数0,小数部分0.5继续计算 0.5*2=1.0 取整数1,小数部分为0,停止…

信创领域认证,来自工信部人才交流中心的PostgreSQL培训班

在国家大力发展信创软件和数据库行业的背景下,PostgreSQL 具有多方面的优势和机遇,具体体现在以下几个方面: 1. 技术优势契合信创需求: PostgreSQL 数据库是一个功能强大、性能稳定、可扩展性强的开源对象关系数据库系统,支持多种数据类型(如数组、JSON、XML 等),方便存储…

Salesforce职业规划:原厂,甲方,乙方,从业者应该如何选择?

Salesforce生态系统蓬勃发展,对不同角色的需求量不断增加。需求方包括使用Salesforce的最终用户(甲方)、实施Salesforce的咨询公司、为Salesforce创建应用程序的AppExchange公司(或ISV),当然还有Salesforce原厂。 Salesforce最终用户(甲方) 2020年,Salesforce的客户数…

3SRB5016-ASEMI三相整流桥3SRB5016

3SRB5016-ASEMI三相整流桥3SRB5016编辑:ll 3SRB5016-ASEMI三相整流桥3SRB5016 型号:3SRB5016 品牌:ASEMI 封装:3SRB-5 批号:2024+ 现货:50000+ 最大重复峰值反向电压:1600V 最大正向平均整流电流(Vdss):50A 功率(Pd):大功率 芯片个数:5 引脚数量:5 安装方式:直插 类…

34-样式迁移

类似于加了一层滤镜基于CNN的样式迁移:如下对于合成图片X,我们希望它的内容和输入的内容图片,放入同一个CNN,在某一个卷积层上,输出的与内容有关的特征能够匹配 同时,,对于样式图片,我们希望合成图片X,和样式图片放入同一个CNN,在某一个卷积层上,输出的与样式有关的…

STM32-ADC外设

1.通道 .规则通道 .注入通道 2.规则序列寄存器 配置通道的采样顺序 3.ADC周期4.ADC转换方式 *单次转换:adc每次只采集某个通道的一个点,如果需要再次采集,就需要重新使能。 *连续转换:adc采集某个通道一个点,转换完成后,再采集第二点。依次类推 4.扫描模式 *单次扫描模式…

SignalR跨域问题解决

本文来自博客园,作者:WantRemake,转载请注明原文链接:https://www.cnblogs.com/SmallChen/p/18406437

字符串类

常用类String基础知识String类的特性String类是一个final类,不能被继承 String类底层是一个final修饰的字符数组,表示不可变的字符序列(final char value[ ]) String的不可变性:当String值改变时,会在常量池中创建新的字符串字符串-创建字面量方式创建 String s1="a…

AI答案之书解来为你解决难题

本文由 ChatMoney团队出品介绍说明 “答案之书智能体”是您贴心的智慧伙伴,随时准备为您解答生活中的种种困惑。无论您在工作中遭遇瓶颈,还是在情感世界里迷失方向,亦或是对个人成长感到迷茫,它都能倾听您的心声,并给予准确且富有启发的回应。 它并非简单地给出答案,而是…

解锁生活密码,AI答案之书解决复杂难题

本文由 ChatMoney团队出品介绍说明 “答案之书智能体”是您贴心的智慧伙伴,随时准备为您解答生活中的种种困惑。无论您在工作中遭遇瓶颈,还是在情感世界里迷失方向,亦或是对个人成长感到迷茫,它都能倾听您的心声,并给予准确且富有启发的回应。 它并非简单地给出答案,而是…