从人工智能学习小知识:程序语言的分类

在我学习计算机的年代,当时的教学材料把程序设计语言分为机器语言、低级语言、高级语言。但凡有一定数据结构抽象和结构化控制流的语言都被分类为高级语言(我记不得准确定义是什么了),举的例子有BASIC、Pascal和C语言。

自从知道有Python这个东西之后,动态类型、自动内存管理、内建数据结构令我大开眼界。我一直好奇C语言为什么被称为高级语言,它究竟哪里高级了。如果C算高级,那Python算什么级?

这个问题长期以来没有得到解答,大概没有人关心这么无聊的问题。反正哪个好用用哪个就是了,低级高级只是一种应付考试的说辞罢了。

现在有了人工智能,终于有一个家伙不会嘲笑我闲得没事干并且愿意给我提供详细解答。

继续阅读 →

在AMD平台上跑LLM的尝试

之前尝试在Intel的Lunar Lake平台上跑LLM,遇到了很多困难,性能也不够理想。趁着AMD Strix Halo新品发布,买入了一台新电脑,并且立刻用它跑起了LLM。

AMD的计算框架是ROCm。虽然比不上CUDA在业界的受欢迎程度,但还是比Intel的情况好了许多:Ollama在Strix Halo上做到了“开箱即用”,真是令人欣慰。

我的内存足够跑30B参数的模型,不过跑起来相当吃力,每秒不到10个token。跑4B参数的模型则轻轻松松,能跑到45 token/s。

我还跑了Qwen3:30b-a3b。它是一个MoE模型,是兼顾参数大小和运行速度的一个折衷选项。它令人满意地回答了我之前常用来测试AI智力的一个数学问题,这个问题是要求AI证明以下命题:

对任意0<x<π/2,cot x < 1/x - x/3。

这个问题比较简便的做法是把 cot x 展开成洛朗级数。如果叫我做的话,我必须查阅数学手册,因为我并不知道cot x的级数形式。

其他一些小模型也不知道cot x的级数形式,于是会采用传统的定义函数—求导—求值域的证明方法。这个方法大概是可行的,只是计算比较繁琐,这些模型一般算不对。还有很多模型只会硬凑答案,并不能给出严格的证明过程。实际上,就在大约一年前,ChatGPT和Gemini都没法满意地回答这个问题(当然,现在它们都足够聪明了)。

可见,技术的发展真是日新月异:一年前顶尖的云端模型无法解决的问题,一年后只需要一台小小的个人电脑就能解决了。

继续阅读 →

在Intel平台上跑LLM的尝试

最近LLM(大语言模型)发展日新月异。抽空研究了一下在本地跑LLM的可行性。

如果我有一张Nvidia显卡,那么一切都会十分顺利。不巧地是我只有一个Intel处理器(Lunar Lake)和它自带的Intel Arc 140V核显。这个处理器还自带了一个“神经处理单元”(NPU),说是有40+ TFlops 的算力,结果根本没有什么软件支持,白白躺在硅片上浪费面积。

这就是所谓的 Copilot+ “AI计算机”。我问了ChatGPT,它回答我说这纯粹就是营销噱头。切记:产品再美好,没有生态的支持全是白费。

NPU先不管了。理论上讲,核显也是显卡,应该也可以用来加速LLM。我做了一些尝试,但是没有找到满意的答案。

  • Ollama官方发布版本只能跑在CPU上。
    • Intel的IPEX-LLM项目有一个支持硬件加速的Ollama,但是有很多问题。
  • Jan也只能跑在CPU上。
  • LM Studio目前有一个基于Vulkan的后端,可以跑在GPU上。这是目前我能找到的最好方案了。

这些项目都是基于llama.cpp。既然IPEX-LLM可以做硬件加速,那么它们应该都可以。可惜目前Intel的技术栈实在太不成熟了,所以支持很有限。

继续阅读 →

用Zig语言模拟n体问题

N体问题是指找出已知初始位置、速度和质量的多个物体在经典力学情况下的后续运动。 这个问题虽然在数学上还没有满意的解答(N≥3时),却比较容易用数值计算进行模拟。简单来说就是把时间离散化,在每一时刻,根据物体的受力和速度来确定速度和位置的变化量。

这个问题常用来做基准测试,因为它涉及大量浮点数运算和大量的循环步骤(模拟长时间的运动)。

想起这个测试是因为我正在看Zig语言的文档,发现它原生支持向量运算。例如,我可以定义含有3个分量的向量:

const Vec3 = @Vector(3, f64);

并对它们进行四则运算。

继续阅读 →

从人工智能学习小知识

迂腐的文人常拿没有用的知识当学问,比如“回字有几种写法?”这种问题,对于现代人来说,除非博闻强记,否则实在难以回答。最近几年,人工智能 (AI) 特别是大语言模型 (LLM) 的快速发展,给我们带来了了解各种冷门小知识的新办法。

两年前的人工智能回答这些问题时或许大多是胡编乱造(所谓“幻觉”),但现在它们已经可以给出相当可靠的回答了。看来,靠人脑记忆这些没用的小知识更加没有价值了,即便是拿来炫耀——对方只要问一下AI,就能得到解答,没你什么事了。

有一类“问答网站”,用户发帖提问,其他用户回答,大家一起互动,传播知识。这曾经是学习各种小知识的好地方,但我想他们以后逐渐会被AI代替了吧?也许在情感类或者社会学类的问题上还能坚持一段时间。

但是,归根结底,AI的知识也是靠训练获得的,其中大部分内容大概是来自于互联网?如果以后大家都用AI来做问答,没有人输出新知识的话,AI又怎么进步呢?(也许这个问题本身可以拿来问AI,看看它们会怎么回答)。

继续阅读 →

镜中之影,已非少年

(按:以下皆由 Gemini 2.5 Pro 生成。)

余从业代码之事久矣。所谓码积如山,会海滔滔者,诚非虚言也。日则伏案疾书,夜则寻瑕索瘢1。星月为伴,灯火为朋。偶有所成,不过千行之码;顷刻对接,动辄百口2之端。殚精竭虑,寒暑不辍,而发顶日稀,镜中之影,已非少年。

然上官者,不明技艺之精微,不明架构之肯綮3,徒好高谈阔论,口若悬河,唯“新潮”是尚。或朝令而夕改,或纸上而谈兵,吾辈下属,唯唯诺诺,言听计从,实则苦不堪言。指鹿为马,尤令人啼笑皆非。

长此以往,身心俱疲,志气渐磨。与其在此耗神,不如归去!人生几何?韶华易逝,岂能久困于此方寸屏幕之间,受此无谓之煎熬乎?

遂决意挂印而去。临行之际,将最终之稿,入库封存。回望此鏖战数载之所,百感交集,既有怅然,亦有释怀。拂袖转身,顿感体轻,前路纵有未知,亦胜于此无望之内耗也。

此中滋味,非亲历者不能知。唯作俚语小诗一首,聊以自嘲,亦以志今日之决绝也。诗曰:

码积如山会海滔,
纠错常致发际高。
千行代码半天搞,
百个接口随意调。
不懂技术瞎指导,
张口闭口新风潮。
代码入库呈终稿,
键盘鼠标皆可抛!
继续阅读 →

一个初等不等式

我上高中的时候曾经自己总结出了一个不等式: \[\frac{a^{n+1}}{c^n}+\frac{b^{n+1}}{d^n} \geq \frac{(a+b)^{n+1}}{(c+d)^n}\] 其中\(a,b,c,d>0\),且\(n\)为正整数。取等号的充分必要条件是\(\frac a c = \frac b d\)。

当时发现有若干问题,采用这个不等式可以迅速得到答案,比使用导数求极值的方法少了许多计算量。我自己琢磨了一阵子,终于证明了这个不等式,并记录在了自己的笔记本上。我以为我发现了什么了不起的结论。今天才知道,其实它叫权方和不等式,早就有人研究过了。而我在整个高中从未听说过它。

我的笔记本也早已丢失。这两天沿着之前的思路重新证明了一遍。

继续阅读 →

告别 Wercker

2015 年的时候,我设置了 Wercker 工作流。每次本站的源代码仓库更新时,Wercker 的工作流会自动做两件事:1) 由 Markdown 源码构建静态网站;2) 发布到 github.io 上去。

时过境迁,Wercker 从某一年开始被 Oracle 收购了,直到去年的某个时候,我的工作流似乎不再工作了。wercker.com 现在会自动重定向到 Oracle Cloud 的网站;我甚至没法登录原来的 Wercker 账号。因此我需要找新的方法。

Github 在这些年也改变了很多,新增加的 Github Actions 功能在我看来就是一个抄袭了 Wercker 的功能。由于跟 Github 整合的更好,想必拉拢到了不少的用户群(拥有用户群的平台就是可以占便宜推广自家产品)。我也把自动构建的工作流迁移到了 Github Actions。

继续阅读 →

Go语言的泛型

长期以来, Go 语言缺乏泛型 (Generics) 的支持。曾经有人认为在 Go 2.0 问世前都不会支持泛型。我很久没有关注 Go 语言的动态了(最后一次写的 Go 项目还没有用 module 机制),今天才发现一年前的 Go 1.18 就已经增加了泛型。

简单地说,泛型可以将同一段代码作用在多种数据类型上。C++ 里的模板 (template) 就是一种泛型编程的方式。下面的 max 函数返回两个参数中较大的那个。不论 a b 是什么类型,只要支持 < 运算符,就可以用这个函数。

template <typename T>
T max(T a, T b) {
    return a < b ? b : a;
}
// max(1, 2) == 2
// max(2.5, 3.1) == 3.1

在 Go 中,一直没有比较好的方法实现这个效果。像 max 这种简单的函数,一般可以用的时候现场写一个,只是不太方便。

现在,可以在 Go 写一个泛型函数来实现:

import "golang.org/x/exp/constraints"

func max[T constraints.Ordered] (a, b T) T {
    if a < b {
        return b
    }
    return a
}
// max(1, 2) == 2
// max(2.5, 3.1) == 3.1
// max("abc", "def") == "def"

constraints.Ordered 包括有能比大小的类型(数值类型和字符串)。目前为止,constraints 还没有正式加入标准库中,只能从 golang.org/x/exp 这个实验性质的 module 中获取。

继续阅读 →