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

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

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