Redis之父自曝用AI写代码,并严厉评价:LLM是一个有知识的“傻瓜”

 2024-03-03 11:04:54  阅读 0

【CSDN编者按】新年伊始,当大家都在做年终总结时,Redis之父也在近日发表了今年的第一篇博文:“2024年伊始,我们来聊聊LLM和编程。” ” 与预想的盘点和回顾不同,本文从一个独立开发者的角度分享了他今年使用AI的经历,并表示:“就我个人而言,我会继续广泛使用LLM。”

作者 | , Redis 作者

翻译 | 编辑| 郑丽媛

出品| CSDN(ID:)

毫无疑问,2023 年对于人工智能来说是特殊的一年。 首先声明一下,这篇文章不是对过去一年LLM(大型语言模型)的回顾,而是谈谈我作为一个独立程序员对AI的见证。 自这项新技术诞生以来,我就广泛使用了它,后来又使用了本地运行的法学硕士。 从个人角度来说,我使用大模型一方面是为了提高编程速度,另一方面希望不再把精力浪费在不值得花功夫的编程方面。

比如,我花了无数个小时寻找陌生但无聊的技术文档,被迫学习过于复杂的API,编写了几个小时后就被丢弃的程序……这些都是我不想做的事情。 ,尤其是现在搜索引擎已经变成了垃圾邮件的海洋,我必须从中筛选才能找到有用的东西。

同时,在编程方面我当然不是新手。 我可以在没有任何帮助的情况下编写代码,并且经常这样做。 但随着时间的推移,我开始越来越多地使用LLM来编写高级代码,尤其是在Java中,而在C中则较少。在频繁使用LLM的过程中,我逐渐学会了何时使用它们以及何时使用它们只会放慢速度。

另外,我还了解到LLM其实有点像维基百科和各种视频课程:对于那些愿意、有能力、有纪律的人来说,LLM的帮助几乎更加强大; 对于那些动力不足、犹豫不决的人来说,即使是强大的LLM也无法帮助他们。 所以我担心,至少目前来说,LLM 只会让本来就很优秀的人变得更好。

但让我们一步一步来。

汇编修改指令_c 反汇编修改代码_汇编反编译成c

全知全能还是鹦鹉学舌?

在这波机器学习的新浪潮中,最令人担忧的现象之一是AI专家对LLM的了解有限。 伟大的思想家发明了神经网络,甚至是自动优化神经网络参数的算法,而硬件可以使用待处理数据的统计知识(先验)和大量的试验和错误来训练越来越大的模型,以近似最佳结果。 ,发现架构比其他方法更有效。 但总体而言,神经网络仍然相当不透明。

由于无法解释为什么法学硕士会开发某些新功能,许多人推测科学家会更加谨慎。 但另一方面,也有一些人严重低估了LLM,认为它们充其量只是稍微高级的马尔可夫链,充其量只能重现训练集中看到的极为有限的变化。 然而,当后来面对证据时,这种“人云亦云”的说法几乎被推翻。

与此同时,也有不少热心人士将现实中不存在的神通归结为LLM——但实际情况是LLM只能对训练时接触过的数据表示空间进行插值。 这不是什么新鲜事。 另外值得一提的是,LLM的插值能力也非常有限。 如果LLM能够在所接触到的所有代码所限制的空间内不断地插值,即使不能真正创新,但仍然可以取代99%的。

幸运的是,事实并非如此。 诚然,LLM 可以编写它从未见过的程序,并巧妙地结合训练集中以一定频率出现的不同想法,但这种能力也非常有限:每当需要微妙的推理时,LLM 就会惨败。 失败。 但话虽如此,LLM仍然代表着AI迄今为止最伟大的成就,这一点无可否认。

愚蠢却无所不知

让我们明确一点:法学硕士充其量只能进行基本的推理,这通常是不准确的,并且常常夹杂着不存在的幻想,但他们确实知识渊博。 在编程和其他拥有高质量数据的领域,法学硕士就像是知道很多东西的愚蠢天才。

与这样的伙伴结对编程是非常麻烦的(对我来说,结对编程本身就很麻烦):他们有一些可笑的想法,而我们必须不断地将自己的想法强加在上面。 当然,如果我们可以用这个博学的“傻瓜”来回答我们向它提出的所有问题,情况就会大不相同。 现有的LLM可能无法弥合知识差距,但如果我们想要处理一个我们不太了解的主题,那么LLM可以将我们从绝对无知的状态中解放出来,让我们知道足够的信息以继续前进独立。

在编程领域,也许二十、三十年前,人们对LLM的能力并不是很感兴趣。 那时候你要掌握几种编程语言、经典算法、十个基础库。 剩下的就取决于你了,你自己的智慧、专业知识和设计技巧。 如果你具备这些要素,那么你就是一个熟练的程序员,几乎可以做任何事情。 随着时间的推移,我们目睹了各种框架、编程语言和库的爆炸式增长。 虽然这种复杂性的爆炸通常是完全不必要和不合理的,但这是事实。 在这种情况下,一个博学的“傻瓜”是一个有价值的盟友。

我举个例子:我使用 Keras 尝试了至少一年的机器学习,然后由于各种原因我切换了。 我已经知道什么是嵌入网络或残差网络,但我不想一步步学习文档(就像我学习 Keras 时所做的那样,当时 Keras 还不存在)。 通过 LLM,编写使用 Torch 的代码变得非常容易。 我只需要清楚地了解我想要组合的模型并提出正确的问题。

例如

我不是在谈论诸如“嘿,X 类中执行 Y 操作的方法是什么?”之类的简单问题。 这样我可能会同意那些对 LLM 持怀疑态度的人。 事实证明,更复杂的模型可以做的事情更加精细。 我可以告诉GPT4:看,这是我在 中实现的神经网络模型,这是我的一批数据,我想调整张量的大小,以便输出批次的函数与神经网络的输入相匹配,并且我想要用这种特殊的方式来表示事物。 您能向我展示进行重塑所需的代码吗? 然后 GPT4 编写代码,我只需在 CLI 中测试张量是否确实具有我需要的维度以及数据的布局是否正确。

还有一个例子。 前段时间,我必须为一些基于 ESP32 的设备实现 BLE 客户端。 经过一番研究,我发现多平台蓝牙编程绑定或多或少无法使用。 解决方案很简单,使用 MacOS 的本机 API 用 C 编写代码。 所以,我必须同时处理两个问题:学习C语言繁琐的BLE API,同时记住如何用C语言编程——我最后一次用C语言编写程序已经是十年前的事了,而我并没有'根本不记得事件循环或内存管理。 等等很多细节。

不过,在LLM的帮助下,我在很短的时间内写完了代码。 最终的代码是这样的。 虽然不漂亮,但至少可以完成任务:

https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m

代码主要是通过剪切和粘贴我想做的事情来编写的,由于我一开始不太明白如何做,所以最初生成的代码无法正常工作,但我能够让LLM向我解释我的问题是什么以及如何做。 修理它。 如果不行的话我可以做吗? 当然可以,但这不仅浪费我的时间,我可能根本不会尝试它,因为它不值得:编写这样一个对我的项目来说次要的程序的努力和好处不值得努力。 大量。

最后一个例子与代码编写无关,而是与数据解释有关。 当时,我想使用我在网上找到的卷积神经网络构建一个脚本,但文档相当缺乏。 该网络的优点是它采用 ONNX 格式,因此我可以轻松提取输入和输出列表及其分配的名称。 我只知道这个卷积神经网络可以检测图像中的某些特征,但对输入图像的格式和大小以及输出的复杂度不太了解。

我首先将 ONNX 网络元数据的输出复制粘贴到 中,并同步我对网络知之甚少的信息。 然后,根据输入的组织方式,输出可能是一个标准化的框,表示与潜在缺陷相对应的图像部分等。经过几分钟的来回,我有了一个能够执行以下操作的脚本网络推理以及将起始图像转换为适合输入的张量所需的代码等等。

一次性程序

与上面类似的例子还有很多,这里不再赘述。 它们的情况和结果基本相同。 除此之外,我还经常遇到另一种情况:我想快速了解一些可以快速验证的东西。 在这种情况下,我会使用法学硕士来加速我对知识的需求。

不过,在不同的情况下,我也让LLM写了所有的代码。 例如,当我需要编写一个一次性程序时,如下所示:

我需要可视化小型神经网络学习过程中的损失曲线。 我在学习过程中向GPT4展示了程序生成的CSV文件的格式,然后我询问如果我在命令行指定多个CSV文件,我将不再需要同一个实验的训练和验证损失曲线,而是比较不同实验的验证损失曲线。 上面的结果是GPT4生成的结果,一共花了30秒。

同样,我需要一个程序来读取 CSV 报告并按月和年对其进行分组。 然后,它会计算一年中不同月份的平均租金价格,同时考虑清洁费用和每次预订的住宿天数。 这个程序对我来说非常有用,但是编写它也很无聊:没有什么有趣的。 所以,我从CSV文件中取出一小部分,将其剪切并粘贴到GPT4上,然后将问题写入LLM来解决,并且它生成的程序第一次就可以工作。 下面我将展示完整的代码:

pythonimport pandas as pdpd.set_option('display.max_rows', None)df = pd.read_csv('listings.csv')reservations = df[df['Type'] == 'Reservation']reservations['Start Date'] = pd.to_datetime(reservations['Start Date'])reservations['Year'] = reservations['Start Date'].dt.yearreservations['Month'] = reservations['Start Date'].dt.monthreservations['Nightly Rate'] = (reservations['Amount'] - reservations['Cleaning Fee']) / reservations['Nights']all_listings = reservations['Listing'].unique()all_years = reservations['Year'].unique()all_months = range(1, 13)index = pd.MultiIndex.from_product([all_listings, all_years, all_months], names=['Listing', 'Year', 'Month'])all_data = pd.DataFrame(index=index).reset_index()merged_data = pd.merge(all_data, reservations, on=['Listing', 'Year', 'Month'], how='left')average_nightly_rates = merged_data.groupby(['Listing', 'Year', 'Month'])['Nightly Rate'].mean().fillna(0)print(average_nightly_rates)

准确地理解如何对本质上相当分散和无序的数据进行分组,需要一些简单的推理:这不是一个法学硕士可以通过简单地重复它所见过的一些语言来解决的问题。 GPT4在训练过程中可能接触过类似的程序,但提示条件肯定和我要求的不一样,但仍然可以写出符合要求的程序代码。 对我来说,这表明法学硕士可以在某种程度上在训练集中各种程序所描绘的空间内进行插值。

在我看来,写这种程序简直就是浪费我的时间,而LLM可以帮我做到,这无疑直接加快了我编写代码的能力:我可以专注于真正重要的事情。

当 LLM 达不到要求时:系统编程

尽管我在使用 LLM 和编程方面取得了成功,但当我编写 C 程序时,我几乎总是使用 LLM 作为一种更方便的文档形式。 我是系统编程方面的专家,在这种情况下,法学硕士只有能够进行复杂的推理才对我有用:然而,在这种情况下,他们几乎总是失败。

让我们从这个实验的提示开始:

概述对布隆过滤器的良好、小型但可行的 C 实现的要求。 关注哈希函数的重要方面,并用高质量的 C 语言编写它们。还要考虑到您的示例实现应该能够存储 100,000 个元素,误报率不超过 5%,并且添加的元素为空 -终止的字符串。

这是输出:

c#include #include #include #include 

#define N 100000 // Number of elements#define P 0.05 // False positive probability#define M (int)(-(N * log(P)) / (log(2) * log(2))) // Size of bit array#define K (int)(M / N * log(2)) // Number of hash functions

unsigned char bitArray[M / 8 + 1];

void setBit(int n) { bitArray[n / 8] |= 1 << (n % 8);}

int getBit(int n) { return bitArray[n / 8] & (1 << (n % 8));}

// Basic hash functions (for demonstration purposes)int hash1(char *str) { int hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; return abs(hash % M);}

int hash2(char *str) { unsigned long hash = 0; int c; while ((c = *str++)) hash = c + (hash << 6) + (hash << 16) - hash; return abs(hash % M);}

void add(char *str) { setBit(hash1(str)); setBit(hash2(str)); // Add more hash functions if needed}

int is_in(char *str) { return getBit(hash1(str)) && getBit(hash2(str)); // Check more hash functions if used}

int main() { char *testStr = "testString"; add(testStr);

if (is_in(testStr)) { printf("%s is probably in the set.\n", testStr); } else { printf("%s is definitely not in the set.\n", testStr); }

return 0;}

从生成的代码来看,GPT4的性能并不是很好。 布隆过滤器被广泛使用,并不是一种奇异的数据结构。 然而,编写一个像样的布隆过滤器显然需要更强的抽象能力,比如找到一种有效的方法将同一个字符串哈希N次并确保哈希值足够不相关。

然而,如果你明确要求 GPT4 修改哈希函数,使其产生 N 个不相关的输出,它会提出一个更好的解决方案:

cunsigned int hash(const char* str, unsigned int hash_id) {    unsigned int hash = 5381;    int c;    while ((c = *str++)) {        hash = ((hash << 5) + hash) + c + hash_id;    }    return hash % BF_SIZE;}

如果 GPT4 自己提出这个想法,它可能会以不同的方式编写布隆过滤器,使用单个哈希函数一次设置 K 位。

即GPT4能够自行完成编写合适且更通用的哈希函数的任务,但在编写布隆过滤器的更大项目中,它未能表现出足够的推理能力,而是输出了两个不同但相似的哈希函数- 这与网络上有关实施不佳的布隆过滤器的示例文章相匹配。

目前LLM的推理能力较弱,如果问题的信息来源稀​​缺,且混杂着许多低质量的信息源,那么输出结果很容易不理想。不过,这并不是孤例。 我曾多次尝试在算法或系统编程领域使用LLM,但结果都很糟糕。

同时,GPT4 能够反汇编它生成的函数(在单独的会话中)并准确理解其目的:

因此,断言LLM在系统编程中没有用处肯定是不准确的。

一个有趣且很大程度上符合预期的观察结果是,在这些情况下,较小模型和较大模型之间的差异确实很大。 我们先来看看两款本土车型的表现。

例如,MoE 模型回答相同的问题如下:

cunsigned int hash(const char* str, unsigned int hash_id) {    unsigned int hash = 5381;    int c;    while ((c = *str++)) {        hash = ((hash << 5) + hash) + c;    }    return hash + hash_id;}

显然,仅仅在最后添加它是一个非常糟糕的解决方案。 从很多方面来说都是一个很好的模型,但对于推理能力本就较弱的LLM来说,目前的规则无疑是:越大越好。

这是我与本地 LLM 编码器的聊天,量化为 4 位,因为我没有足够的 RAM 来使用更高精度的模型。 不过,由于它有340亿个参数,所以在这个问题上的推理能力似乎相当超前:说白了,添加到最后可能会导致分布不均匀,尤其是太大或者分布不均匀的时候,而建议使用位运算会混入其中。

cunsigned int hash(const char* str, unsigned int hash_id) {    unsigned int hash = 5381;    int c;    while ((c = *str++)) {        hash = ((hash << 5) + hash) ^ c + hash_id; // Using XOR to mix in the hash_id     }    return (hash ^ hash_id); // Mixing the hash_id one more time at the end}

结果,至少在我的 M1 Max 上,效果非常好,并且它还使用 XOR 来混合总和结果。 在这种情况下,我提供了问题的线索,这当然对模型有帮助,但模型确定了问题的真正根源,并提出了有效的解决方案——这是书籍、文档或谷歌搜索无法做到的。 意识到了。

无论这是插值的原始结果还是从另一个角度来看,不可否认的是,模型确实执行了某种形式的推理,我们可以从中受益,找到问题的根源和解决方案。 因此,无论人们如何看待法学硕士,断言它们对程序员没有帮助都是极其仓促的。

但同时,我过去几个月的经验表明,对于系统编程来说,如果你已经是一名经验丰富的程序员,LLM几乎永远不会提供有效的解决方案。 例如,我当前的项目涉及编写一个以 GGUF 格式读取和写入文件的库,这是 llama.cpp 加载量化模型的格式。 最初,为了了解量化编码的工作原理,我尝试使用 ,但后来我决定对 llama.cpp 的代码进行逆向工程:这样速度更快。

如果LLM为系统程序员提供了适当的帮助,那么在看到数据编码“”声明和解码函数时应该可以重建数据格式文档。 llama.cpp的功能很小,完全满足GPT4的要求,但是输出结果完全没用。 这种情况下,我们只能像以前那样:拿出纸和笔,阅读代码,看看解码器提取的位被注册到哪里了。

透过外表看到本质

当我这么说时,我可能很直率,但这是事实:当今的大多数编程工作都涉及以略有不同的形式重复相同的事情,而这并不需要高水平的推理。 尽管法学硕士受到背景的严重限制,但他们确实很擅长做到这一点。

这应该让程序员思考:这样的程序值得写吗? 当然,你会得到报酬,可能相当慷慨,但如果你能通过法学硕士完成部分工作,那么也许五年或十年后,这份工作并不是最适合你的地方。

其次,LLM是否真的具有某种推理能力,还是只是“人云亦云”? 也许有时它们看起来是推论性的,符合符号学家所说的“能指”的概念,但实际上它是一种并不存在的意义。 那些长期与LLM打交道并深知其局限性的人应该深刻地意识到这一点:他们整合过去接触过的内容的能力远远超过了他们随机输出单词的能力。 虽然LLM的大部分训练主要发生在预训练期间,但在预测下一个token时,大模型仍然基于目标创建某种形式的抽象模型。 这个模型可能是脆弱的、支离破碎的、不完善的,但通过实际观察,我们会发现这种能力一定是存在的。 如果我们的数学定理值得怀疑,而最伟大的专家常常持有相反的意见,那么“眼见为实”对我们来说似乎是明智的。

最后我想说:既然都结束了,不使用LLM编程还有什么意义呢? 向法学硕士提出正确的问题是一项基本技能,你练习得越少,人工智能对你工作的帮助就越小。 此外,培养描述问题的能力在与其他人交谈时也很有用。 有时候LLM并不是唯一一个不明白我们想说的话的人。 沟通不畅是一个很大的限制。 许多程序员虽然在自己的特定领域非常有能力,但沟通能力很差。

目前, 搜索一团糟:使用 LLM,即使只是作为压缩文档形式,也是一个不错的选择。 就我个人而言,我将继续广泛使用LLM,我从来不喜欢学习通信协议的神秘细节,并且讨厌那些想炫耀自己有多优秀的人编写的库的复杂方法 - 对我来说,这一切似乎是“智力垃圾”,谢谢LLM每天把我从这一切中拯救出来。

原文链接:

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码