美文网首页
基于改进CRNN的代码&缩进排版检测系统(源码&教程)

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

作者: 群山科技 | 来源:发表于2022-12-17 19:56 被阅读0次

    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.代码实现

    # 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).

    相关文章

      网友评论

          本文标题:基于改进CRNN的代码&缩进排版检测系统(源码&教程)

          本文链接:https://www.haomeiwen.com/subject/dclsqdtx.html