GitHub有300多种编程语言,从Python,Java和Javascript等知名语言到
Befunge等神秘语言,仅少数人知道。
按存储库数量排名前10位的GitHub托管编程语言GitHub面临的问题之一是对不同编程语言的认识。 将一些代码放置在存储库中时,识别其类型非常重要。 出于搜索,漏洞警报,语法突出显示以及向用户显示存储库内容的结构性原因,这是必需的。
乍一看,语言识别是一项简单的任务,但事实并非如此。
语言学家是我们目前用于在GitHub上定义编程语言的工具。 Linguist是一个Ruby应用程序,它使用各种语言识别策略,包括名称信息和文件扩展名。 此外,它还考虑了Vim或Emacs模型以及文件顶部的内容(shebang)。 语言学家通过启发式方法处理语言歧义,如果无法解决问题,则使用对少量数据进行训练的朴素贝叶斯分类器。
尽管语言学家在文件级别上预测得很好(准确度为84%),但是当文件命名异常时,一切都将中断,而在文件没有扩展名的情况下,甚至会破坏更多。 这使得Linguist对于诸如GitHub Gist或README中的代码段,错误和提取请求之类的内容毫无用处。
为了使语言定义从长远来看更加清晰,我们开发了一种名为OctoLingua的机器学习分类器。 它基于人工神经网络(ANN)架构,可以处理非平凡场景中的语言预测。 该模型的当前版本可以预测GitHub上排名前50位的编程语言,并在准确性上超过Linguist。
有关OctoLingua的更多详细信息
OctoLingua是使用Keras和TensorFlow后端从头开始用Python编写的-它的创建是准确,可靠和易于维护的。 在这一部分中,我们将讨论我们的数据源,模型架构和OctoLingua性能测试。 我们还将讨论增加识别一种新语言的能力的过程。
资料来源
当前版本的OctoLingua已经过从
Rosetta Code和内部内部众包存储库中获取的文件的培训。 我们将语言集限制为GitHub上最受欢迎的50种语言。
Rosetta Code是一个很好的起始数据集,因为它包含为执行相同任务而编写的源代码,但使用不同的编程语言。 例如,用于生成
斐波那契数的代码以C,C ++,CoffeeScript,D,Java,Julia等形式呈现。 但是,这些语言的覆盖范围是多种多样的:对于某些编程语言,只有几个带有代码的文件,而对于另一些语言,这些文件仅包含很少的代码。 因此,有必要用一些其他资源补充我们的训练数据集,从而显着提高语言的覆盖范围和最终模型的有效性。
我们添加新语言的过程并非完全自动化。 我们以编程方式从GitHub上的公共存储库中编译源代码。 我们仅选择那些符合最低资格标准的存储库,例如覆盖目标语言和特定文件扩展名的最小派生数。 在数据收集的这一阶段,我们使用Linguist的分类定义存储库的主要语言。
症状:基于先前的知识
传统上,基于记忆的体系结构(例如递归神经网络(RNN)和长期短期记忆网络(LSTM))用于使用神经网络解决文本分类问题。 但是,由于编程语言在词汇,文件扩展名,结构,导入库的样式以及其他细节方面的差异,迫使我们提出了一种使用所有这些信息的不同方法,以表格形式提取了一些符号来训练我们的分类器。 属性检索如下:
- 文件中的前5个特殊字符
- 文件中的前20个字符
- 文件扩展名
- 文件源代码中使用的特定特殊字符的存在,例如冒号,花括号,分号
模型人工神经网络(ANN)
我们将上述因素用作使用Keras与Tensorflow后端构建的两层神经网络的输入。
下图显示了特征提取步骤为我们的分类器创建了n维表条目。 随着信息在网络各层之间的移动,信息通过删除进行排序,结果是51维输出,这表示此代码是用GitHub上前50种语言编写的。 它还显示了代码未使用50种语言编写的可能性。
源模型的ANN结构(50种语言+ 1种“其他”语言)我们使用了源数据库的90%进行培训。 同样,在模型的训练步骤中,文件扩展名的一部分被删除,因此该模型可以从文件的词汇表中准确学习,而不能从文件的扩展名中学习,因为它们很好地预测了编程语言。
性能测试
OctoLingua vs语言学家
在下表中,我们显示了在同一测试集(原始数据源的10%)上计算出的OctoLingua和Linguist的
F1得分 (准确性和完整性之间的谐和平均值)。
这里显示了三个测试。 在第一个测试中,数据集完全没有被触及。 第二,文件扩展名被删除; 在第三个文件中,混合了文件扩展名以便混淆分类器(例如,Java文件可能具有扩展名“ .txt”,而Python文件可能具有扩展名“ .java”。
在我们的测试套件中,改组或删除文件扩展名的直觉是评估在删除或误导键标签时OctoLingua在文件分类中的可靠性。 不太依赖扩展名的分类器对于分类日志和代码片段非常有用,因为在这种情况下,人们通常不提供有关扩展名的准确信息(例如,许多与代码相关的日志都具有txt扩展名)。
下表显示了OctoLingua在各种条件下如何具有良好的性能,当我们假设该模型主要从代码的词汇而不是从元信息(例如文件扩展名)学习时。 同时,一旦缺少有关正确文件扩展名的信息,语言学家就会错误地确定语言。
在同一测试套件上的OctoLingua与语言学家的表现训练模型时删除文件扩展名的效果
如前所述,在训练过程中,我们从数据中删除了一定百分比的文件扩展名,以使模型从文件的词汇中学习。 下表显示了我们的模型的性能,其中在培训期间删除了不同比例的文件扩展名。
OctoLingua的性能以及不同百分比的已删除文件扩展名请注意,在带有扩展名的文件上训练的模型对没有扩展名或具有混合扩展名的测试文件的有效性要比对常规测试数据的效果明显差。 另一方面,当在删除了部分文件扩展名的数据集上训练模型时,在修改后的测试集上模型的性能不会降低很多。 这证实了在培训期间从文件的一部分中删除扩展名会促使我们的分类器从代码词汇中学习更多。 它还显示文件扩展名趋于占主导地位,并阻止了特色内容的加权。
新语言支持
向OctoLingua添加新语言是一个相当简单的过程。 它从搜索开始并以一种新的语言获得大量文件(我们可以通过编程方式进行操作,如“数据源”部分所述)。 这些文件分为培训和测试套件,然后通过我们的预处理器和特征提取器。 新数据集将添加到现有池中。 该测试套件使我们能够确保模型的准确性仍然可以接受。
在OctoLingua中添加新语言我们的计划
OctoLingua当前处于“高级原型开发阶段”。 我们的语言分类机制已经可靠,但是还不支持GitHub上所有可用的编程语言。 除了扩展语言支持(这并不难)之外,我们还努力为语言检测提供各种级别的代码详细信息。 我们当前的实现方式已经允许我们在稍加修改机器学习机制的情况下对代码片段进行分类。 同样,将模型带入可以可靠地检测和分类嵌入式语言的阶段似乎并不困难。
我们也正在考虑发布模型的源代码,但是我们需要社区的要求。
结论
我们开发OctoLingua的目标是创建一种服务,以通过源代码在不同的详细级别上提供可靠的语言定义:从文件或代码片段的级别到行级别的语言的潜在定义和分类。 我们在此服务上所做的所有工作旨在为开发人员的日常开发工作提供支持,并为编写高质量代码创造条件。
如果您有兴趣为我们的工作做出贡献,请随时通过Twitter
@github与我们联系!