由于图床过期,图片无法正常显示,有图阅览请移步以下Gitee/Github网址,文末获取【源码和部署教程】或者通过以下Gitee/Github的文末邮件获取

Gitee(推荐国内访问): https://gitee.com/qunmasj/projects

Github(推荐国外访问): https://github.com/qunshansj?tab=repositories



1.研究背景

代码的识别与自动重构是近年来软件工程的热点领域之一,而重复代码是一种在软件工程中较为常见的代码.本文在基于文本的重复代码识别方法的基础上,通过词法分析对特定的Token作出处理后再对源代码进行对比,最后通过语法树的对比来对结果进行过滤以降低误报率.测试结果表明该方法对于重复代码有着较好的识别效果.对重复代码的自动识别算法研究有着借鉴意义,在软件的质量、维护等领域上也具有广泛的应用需求.

2.图片演示

2.png

3.png

3.视频演示

基于改进CRNN的代码&缩进排版检测系统(源码&教程)_哔哩哔哩_bilibili

4.CRNN简介

是目前较为流行的图文识别模型,可识别较长的文本序列, 它利用BLSTM和CTC部件学习字符图像中的上下文关系, 从而有效提升文本识别准确率,使得模型更加鲁棒。 CRNN是一种卷积循环神经网络结构,用于解决基于图像的序列识别问题,特别是场景文字识别问题。 文章认为文字识别是对序列的预测方法,所以采用了对序列预测的RNN网络。通过CNN将图片的特征提取出来后采用RNN对序列进行预测,最后通过一个CTC的翻译层得到最终结果。说白了就是CNN+RNN+CTC的结构。

CRNN 全称为 Convolutional Recurrent Neural Network,主要用于端到端地对不定长的文本序列进行识别,不用先对单个文字进行切割,而是将文本识别转化为时序依赖的序列学习问题,就是基于图像的序列识别。

原文链接:https://blog.csdn.net/bestrivern/article/details/91050960
image.png

5.CRNN改进

基于mobilenetv3的CRNN

mobilenetv3没有官网实现,高星实现: mobilenetv3为基础模型。
如下图红框部分所示,将倒数3个s 由2改为(2,1)
image.png

基于efficientnet的CRNN

efficientnet没有官网实现,高星实现: efficientnet为基础模型
如下图红框部分所示,将倒数3个s 由s22改为s21
image.png

6.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# CRNN网络模型
#################### 自己写的代码这里开始 ###################
class CRNN(object):
def __init__(self,
num_classes, # 类别数量
label_dict): # 标签字典
self.outputs = None # 输出
self.label_dict = label_dict # 标签字典
self.num_classes = num_classes # 类别数量

def name(self):
return "crnn"

def conv_bn_pool(self, input, group, # 输入,组
out_ch, # 输入通道数
act="relu", # 激活函数
param=None, bias=None, # 参数、权重初始值
param_0=None, is_test=False,
pooling=True, # 是否执行池化
use_cudnn=False): # 是否对cuda加速
tmp = input

for i in six.moves.xrange(group):
# for i in range(group): # 也可以
# 卷积层
tmp = fluid.layers.conv2d(
input=tmp, # 输入
num_filters=out_ch[i], # num_filters (int) - 滤波器(卷积核)的个数。和输出图像通道相同。
filter_size=3,##滤波器大小
padding=1,##填充大小
param_attr=param if param_0 is None else param_0,##指定权重参数属性的对象
act=None,
use_cudnn=use_cudnn)
# 批量归一化
tmp = fluid.layers.batch_norm(
input=tmp, # 前面卷基层输出作为输入
act=act, # 激活函数
param_attr=param, # 参数初始值
bias_attr=bias, # 偏置初始值
is_test=is_test) # 测试模型
# 根据传入的参数决定是否做池化操作
if pooling:
tmp = fluid.layers.pool2d(
input=tmp, # 前一层的输出作为输入
pool_size=2, # 池化区域
pool_type="max", # 池化类型
pool_stride=2, # 步长
use_cudnn=use_cudnn,
ceil_mode=True) # 输出高度计算公式
return tmp

# 包含4个卷积层操作
def ocr_convs(self, input,
regularizer=None, # 正则化
gradient_clip=None, # 梯度裁剪,防止梯度过大
is_test=False, use_cudnn=False):
###创建一个参数属性对象,用户可设置参数的名称、初始化方式、学习率、正则化规则、是否需要训练、梯度裁剪方式、是否做模型平均等属性。
b = fluid.ParamAttr(
regularizer=regularizer,
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.0))
w0 = fluid.ParamAttr(
regularizer=regularizer,
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.0005))
w1 = fluid.ParamAttr(
regularizer=regularizer,
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.01))

tmp = input

# 第一组卷积池化
tmp = self.conv_bn_pool(tmp,
2, [16, 16], # 组数量及卷积核数量
param=w1,
bias=b,
param_0=w0,
is_test=is_test,
use_cudnn=use_cudnn)
# 第二组卷积池化
tmp = self.conv_bn_pool(tmp,
2, [32, 32], # 组数量及卷积核数量
param=w1,
bias=b,
is_test=is_test,
use_cudnn=use_cudnn)
# 第三组卷积池化
tmp = self.conv_bn_pool(tmp,
2, [64, 64], # 组数量及卷积核数量
param=w1,
bias=b,
is_test=is_test,
use_cudnn=use_cudnn)
# 第四组卷积池化
tmp = self.conv_bn_pool(tmp,
2, [128, 128], # 组数量及卷积核数量
param=w1,
bias=b,
is_test=is_test,
pooling=False, # 不做池化
use_cudnn=use_cudnn)
return tmp

# 组网
def net(self, images,
rnn_hidden_size=200, # 隐藏层输出值数量
regularizer=None, # 正则化
gradient_clip=None, # 梯度裁剪,防止梯度过大
is_test=False,
use_cudnn=True):
# 卷积池化
conv_features = self.ocr_convs(
images,
regularizer=regularizer,
gradient_clip=gradient_clip,
is_test=is_test,
use_cudnn=use_cudnn)
# 将特征图转为序列
sliced_feature = fluid.layers.im2sequence(
input=conv_features, # 卷积得到的特征图作为输入
stride=[1, 1],
# 卷积核大小(高度等于原高度,宽度1)
filter_size=[conv_features.shape[2], 1])
# 两个全连接层
para_attr = fluid.ParamAttr(
regularizer=regularizer, # 正则化
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.02))
bias_attr = fluid.ParamAttr(
regularizer=regularizer, # 正则化
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.02))
bias_attr_nobias = fluid.ParamAttr(
regularizer=regularizer, # 正则化
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.02))

fc_1 = fluid.layers.fc(
input=sliced_feature, # 序列化处理的特征图
size=rnn_hidden_size * 3,
param_attr=para_attr,
bias_attr=bias_attr_nobias)
fc_2 = fluid.layers.fc(
input=sliced_feature, # 序列化处理的特征图
size=rnn_hidden_size * 3,
param_attr=para_attr,
bias_attr=bias_attr_nobias)

# 双向GRU(门控循环单元,LSTM变种, LSTM是RNN变种)
gru_foward = fluid.layers.dynamic_gru(
input=fc_1,
size=rnn_hidden_size,
param_attr=para_attr,
bias_attr=bias_attr,
candidate_activation="relu")
gru_backward = fluid.layers.dynamic_gru(
input=fc_2,
size=rnn_hidden_size,
is_reverse=True, # 反向循环神经网络
param_attr=para_attr,
bias_attr=bias_attr,
candidate_activation="relu")
# 输出层
w_attr = fluid.ParamAttr(
regularizer=regularizer,
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.02))
b_attr = fluid.ParamAttr(
regularizer=regularizer,
gradient_clip=gradient_clip,
initializer=fluid.initializer.Normal(0.0, 0.0))

fc_out = fluid.layers.fc(
input=[gru_foward, gru_backward], # 双向RNN输出作为输入
size=self.num_classes + 1, # 输出类别
param_attr=w_attr,
bias_attr=b_attr)

self.outputs = fc_out
return fc_out

def get_infer(self):
# 将CRNN网络输出交给CTC层转录(纠错、去重)
return fluid.layers.ctc_greedy_decoder(
input=self.outputs, # 输入为CRNN网络输出
blank=self.num_classes)

7.系统整合

下图完整源码&环境部署视频教程&自定义UI界面
1.png
参考博客《基于改进CRNN的代码&缩进排版检测系统(源码&教程)》

8.参考文献


[1]杨勋姮,段明璐.软件缺陷分析技术的研究[J].软件.2018,(2).DOI:10.3969/j.issn.1003-6970.2018.02.019.

[2]段明璐.软件故障树算法建模的研究[J].软件.2018,(2).DOI:10.3969/j.issn.1003-6970.2018.02.015.

[3]印杰,李千目.软件代码漏洞的电子取证技术综述[J].软件.2015,(12).DOI:10.3969/j.issn.1003-6970.2015.12.012.

[4]翁秀木.一个通用的软件质量评估指标体系[J].软件.2015,(3).DOI:10.3969/j.issn.1003-6970.2015.03.012.

[5]史庆庆,孟繁军,张丽萍,等.克隆代码技术研究综述[J].计算机应用研究.2013,(6).DOI:10.3969/j.issn.1001-3695.2013.06.004.

[6]郭婧,吴军华.基于程序依赖图的克隆检测及改进[J].计算机工程与设计.2012,(2).DOI:10.3969/j.issn.1000-7024.2012.02.036.

[7]于冬琦,吴毅坚,彭鑫,等.基于相似性度量的面向对象程序方法级克隆侦测[J].电子学报.2010,(z1).

[8]于冬琦,彭鑫,赵文耘.使用抽象语法树和静态分析的克隆代码自动重构方法[J].小型微型计算机系统.2009,(9).

[9]James R. Cordy,Rainer Koschke,Chanchal K. Roy.Comparison and evaluation of code clone detection techniques and tools: A qualitative approach[J].Science of Computer Programming.2009,74(7).

[10]Matthias Rieger,Stephane Ducasse,Oscar Nierstrasz.On the effectiveness of clone detection by string matching[J].Journal of Software Maintenance & Evolution: Research & Practice.2006,18(1).


如果您需要更详细的【源码和环境部署教程】,除了通过【系统整合】小节的链接获取之外,还可以通过邮箱以下途径获取:

1.请先在GitHub上为该项目点赞(Star),编辑一封邮件,附上点赞的截图、项目的中文描述概述(About)以及您的用途需求,发送到我们的邮箱

sharecode@yeah.net

2.我们收到邮件后会定期根据邮件的接收顺序将【完整源码和环境部署教程】发送到您的邮箱。

【免责声明】本文来源于用户投稿,如果侵犯任何第三方的合法权益,可通过邮箱联系删除。