Redian新闻
>
四种自制代码生成对比:哪种方法最适合微调?

四种自制代码生成对比:哪种方法最适合微调?

科技

在过去的几周里,我们尝试自己结合开源的大模型 LLaMA、ChatGLM 进行模型微调,除了业务部分的探索,还有很大一部分在技术方面的探索,诸如于代码辅助生成

在尝试了不同场景和业务模式的代码生成,我们探索了四种不同方式,后续可能还会有一些,但是差异可能不大。

四种方法的太长不读版:

  • 代码示例生成法。通过输入示例文本和目标代码,让 AI 模型根据代码规律生成新的代码。

  • 测试驱动生成法。通过输入测试代码,让 AI 模型根据测试代码生成对应的业务代码。

  • 元数据辅助生成法。通过提供更多的元数据信息,如变量类型、函数参数等,让AI模型更精确地生成通用代码。

  • 信息匹配生成法。如通过结合数据源中的表信息,让 AI 模型根据需求生成 SQL 语句。

PS:训练步骤和数据集见:https://github.com/unit-mesh/unit-minions 。

AI 研发提效的探索:四种方式

在学习炼丹(训练模型)的同时,我们也在探索更有效的方式。

代码示例生成法:文本生成 SQL

这种方式通过输入一些示例文本和目标代码,让 AI 模型学习如何生成符合目标的代码。模型会根据示例代码和目标代码的特征和规律,学习生成类似的代码。由于的是输入文本,所以生成的代码也存在一定的随机性。这种方式适用于生成通用代码,例如生成一些常见的数据处理、图形化界面等代码。

我们找了一个 HuggingFace 上的数据集,训练了一个 LLaMA 的 LoRA。作为一个失败的版本,由于数据集太小、质量不太高,所以生成的也比较奇怪。

示例输入:

  1. evaluate("text to sql", "谁是最美丽的人", 0.1, 0.75, 40, 4, 512)

示例输出:

  1. SELECT MOST BEAUTIFUL FROM table WHERE BEAUTIFUL = 最美丽的人

比较明显的问题是,由于不知道对应的表等信息,所以生成出来的永远不尽人意。理想的方式是,训练时候加入表信息,并进行预处理融入表信息等等。

测试驱动生成法:测试用例生成

这种方式是将测试代码作为输入,生成适合测试代码的业务代码。这种方式能够更准确地生成适合特定业务场景的代码,因为测试代码通常会包含业务场景的特征和规律。同时,由于输入的测试代码比较固定,所以生成的代码也比较稳定。这种方式适用于生成适合测试代码的业务代码。

我们自己写了测试方法的解析,以及对应的类信息,来更好地生成测试代码,数据集大概在 8000 个。

输入示例:

  1. evaluate("write test", """

  2. public Set<String> listFilesUsingJavaIO(String dir) {

  3. return Stream.of(new File(dir).listFiles())

  4. .filter(file -> !file.isDirectory())

  5. .map(File::getName)

  6. .collect(Collectors.toSet());

  7. }

  8. """, 0.1, 0.75, 40, 4, 512)

输出示例:

  1. @Test

  2. public void shouldListFilesUsingJavaIO() {

  3. Set<String> files = ListFilesUsingJavaIO.listFilesUsingJavaIO(new File("dir"));

  4. assertThat(files, containsInAnyOrder("file1", "file2", "file3"));

  5. }

从结果来说,既然没有给对应的类信息,生成的测试用例还是可以的。不过,还存在一定的数据集太小,以及 LLaMA 权重的问题,导致生成的代码有一定的问题。

元数据辅助生成法:代码辅助生成

结合元信息的代码生成方式会提供更多的元数据信息,如变量类型、函数参数等,来帮助模型更准确地生成代码。这种方式能够更准确地生成符合特定需求的代码,因为提供的元数据信息能够帮助模型更好地理解代码的语义和结构。这种方式适用于生成通用代码。

我们采用的方式是让 LLM 学会填空,算是比较经典的方式。为了避免大小导致的问题,我们探索了一下给 API 的行数,只提供类的信息。

输入示例:

  1. evaluate("Implement the method updatePostCommentsSize", "PostRepository()\n- methods: findById(Long): Optional<Post>, updatePostCommentsSize(int, Long): void, findAllByPostTopics(String): List<Post>, findDistinctByPostTopics(String): List<Post>", 0.1, 0.75, 40, 4, 512)

输出示例:

  1. public class PostRepository {

  2. public void updatePostCommentsSize(int size, Long postId) {

  3. Post post = findById(postId);

  4. if (post == null) {

  5. return;

  6. }

  7. post.setPostCommentsSize(size);

  8. save(post);

  9. }

  10. }

从结果来说,写 CRUD 的代码质量还行,不过考虑到数据集来说,还是有进一步的改进空间。由于的缺点是,为了实现这样的功能,还需要进一步和各类工具整合到一起。

信息匹配生成法:文本转 Repository

结合表信息的 SQL + Repository 生成方式会通过多步骤结合数据源中的表信息来生成符合需求的 SQL + Repository 语句。这种方式能够更准确地生成符合特定需求的 SQL 语句,因为结合了数据表信息,能够更好地理解数据表的结构和关系。这种方式适用于生成符合需求的 SQL 语句。

我们采用的方式是会对输入完的结果进行预处理,以生成一个带表等信息的文本,并添加表的信息。如此一来,生成的数据会更加准确。

原数据格式示例:

  1. instruction:

  2. 我想查找特定月份(monthly_id)下在某个日期(date)之前的所有费用(expense),以方便了解特定月份内的开销情况。

  3. input:

  4. data class ExpenseEntity(....)

  5. output:

  6. @Query("SELECT * FROM expense WHERE monthly_id = :recurringExpenseId AND date < :beforeDate")

  7. suspend fun getAllExpensesForRecurringExpenseBeforeDate(recurringExpenseId: Long, beforeDate: LocalDate): List<ExpenseEntity>

输入示例:

  1. evaluate("text to kotlin repository with class", "我想查询指定年龄的用户(User)的博客数量。\n ###data class User(var age: Int, val blogId: Int) data class Post(val title: String)###", 0.1, 0.75, 40, 4, 512)

对应的输出示例:

  1. @Query("SELECT COUNT(*) FROM User WHERE age = :age")

  2. abstract fun getBlogCount(age: Int): Long

在这个试验里,虽然生成的 Repository 代码都比较让人满意。但是呢,由于人类普遍喜欢用 SELECT * 就导致生成出来的代码各种 SELECT *,所以也就没有那么满意了。

差异对比

这四种方式各有优缺点,适用于不同的场景和需求:

  • 方式 1:代码示例生成法。这种方式的优点是简单直接,不需要额外的信息或步骤。缺点是生成的代码可能不够准确或完整,需要人工检查和修改。适用于一些简单的代码生成任务,或者作为初步的代码草稿。

  • 方式 2:测试驱动生成法。这种方式的优点是能够根据测试代码的要求,生成满足条件的业务代码。缺点是需要提供高质量的测试代码,否则可能导致错误或低效的业务代码。适用于一些有明确测试标准和规范的代码生成任务,或者作为代码优化和重构的辅助工具。

  • 方式 3:元数据辅助生成法。这种方式的优点是能够利用更多的上下文信息,提高代码生成的准确性和可读性。缺点是需要收集和提供更多的元数据信息,增加了数据准备和处理的工作量。适用于一些有复杂逻辑和结构的代码生成任务,或者作为代码质量和规范性的保障手段。

  • 方式 4:信息匹配生成法。这种方式的优点是能够根据数据源中的表结构和关系,生成符合需求和规范的 SQL 语句。缺点是需要多步骤的交互和反馈,增加了用户和模型之间的沟通成本。适用于一些有特定数据源和查询需求的 SQL 生成任务,或者作为 SQL 学习和教育的辅助工具。

结果如下表所示:

方式输入随机性附加信息应用场景
代码示例示例文本和目标代码较高生成通用代码
测试驱动测试代码类信息生成适合测试代码的业务代码
元数据辅助元数据信息中等变量类型、函数参数等元数据信息等生成通用代码
信息匹配数据库中的表信息变量类型、函数参数等元数据信息生成符合需求的SQL语句

只有提供更丰富的信息,AI 才能生成更准确的代码。

小结

本文介绍了四种 AI 代码生成微调方式,包括代码示例生成法、测试驱动生成法、元数据辅助生成法和信息匹配生成法。每种方式都有其优缺点和适用场景,但都需要提供更多的信息才能生成更准确的代码。

欢迎自己动手试验:https://github.com/unit-mesh/unit-minions

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
6种方法配置Linux环境变量,哪种更丝滑?Belmont公私校大对比:Belmont Hill vs Belmont HighChatGPT教我避开敏感话题, AI卅年乌鸦变凤凰攻略|香港市区往返机场,这种方法最快最方便!Replit:“人人可编程”的探索者,代码生成时代的Figma四种不良贷款出表方式对比分析美国费城宾夕法尼亚大学,校园建筑大观春假在即,“最适合带娃”城市榜单出炉 | 拉斯维加斯竟上榜,而这个城市最不适合!调整生活状态的四种方法把激光集成到芯片上的四种方法最全面的澳洲父母移民详细解析,到底哪种签证最适合,最快速让父母移民!AMINO四月新鲜事:硅谷李师傅新书《投资的逻辑》热销中|喜迎又一独角兽Replit代码生成滋养生命的四种方式马斯克:Twitter将于3月31日开源所有推荐机制代码硬核观察 #993 Hugging Face 发布免费的代码生成 AI《黑暗荣耀》阶层对比:富人浑身大牌无法无天,穷人穿黑衣隐忍复仇…5大主流方案对比:MySQL千亿级数据线上平滑扩容实战一个人内心强大的四种方法MyBatis-Plus 可视化代码生成器来啦,让你的开发效率大大提速!!中美俄大运产能对比:中国运20加速交付位列第一医生:这四种自费疫苗,建议给孩子打!TKDE 2023 | 交叉学科项目申请书学科代码生成移民加拿大的N种方式里,哪种适合你?2023年移民加拿大方法大全,你最适合哪一种?天气渐热没装空调?男子花$6.6美元“自制冷气” 让室友一觉到天亮各大银行存款对比:数风流银行,还看存款美国哪里退休最好?ChatGPT怎么说的,好像有点道理祝贺Replit估值11.6亿美金【AMINO被投企业】AI代码生成平台Replit融资9740万美金安达卢西亚的秋阳下~格拉纳达独处,是一个人的清欢- 叔本华从此告别繁琐的模型微调,LLM-Adapters助力NLP任务快速高效微调!宝宝哭闹打滚和大人唱反调?这 3 个方法要掌握好美国人为啥胖?英美对比:食物份量差异明显ChatGPT要怎么微调?MIT韩松团队新作告诉你!对比:美国超市 VS 中国超市竟有如此多不同?
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。