• A Story About Litchi

    Litchi 项目 离开 CSDN AI 组以后,我终于有钱买了一台可以运行 Ollama 的工作机。自此以后的近一年间,我一直在尝试做一个适合自己的 AI 工作环境。 尝试和探索 这个方向我的第一个尝试是一个名为 blue-shell 的 ollama 客户端。这是一个简单的对话 repl,我仅仅是在 console 环境将 markdown 处理为更容易阅读的形式。 第二个尝试是名为 In The Shell 的 java 桌面程序,它支持预定义的 prompt 模板,与 Ollama 对话并将对话历史格式化展现。这已经是我每日必用的工具,各种操作习惯都是我为自己量身定制的,我甚至还给它写了一个语音输入。 但是我还是想再写一个,这是因为我需要一个对markdown编辑和技术写作高度友好的环境。我需要它可以将对话过程与编程和写作紧密的结合在一起,并且自然的将AI的对话过程集成进来。并且,In The Shell 没有保存历史记录的功能。我当时只是写 TENSOR DANCER 的间隙,随时增补一些小功能,满足我即时的需要。这使得 In The Shell 始终处在凑合能用的状态。比如,我要拿出 AI生成的内容时,仅需要双击对应的cell,它就会把内容复到剪贴板,这在我用它翻译文档的时候非常方便,但是如果我让AI给我写单元测试,我没有办法直接选中格子中的一部分内容。 因为 In The Shell 也是我拿来练习 JavaFX... [Read More]
  • GGML PCA

    主成分分析 主成分分析(principal components analysis)是一类非常常见的算法,广泛应用于各种需要信息压缩的场景。虽然《深度学习》一书称之为“简单的机器学习算法”,但是PCA通常可以通过确定的数值算法实现。 概略来说,PCA是找到一个映射算法,将高维空间的样本集合在尽量不损失信息的前提下,映射到更低的维度,从N维空间映射到M维空间,可以表示为一个 $M*N$的矩阵。PCA的目的就是通过分析样本集合,解出这个映射矩阵。 这个求解过程主要有这样几个步骤: 将样本集合表达为$样本数特征数$($AF$)的矩阵 将这个矩阵规范化,使后续步骤中我们可以得到一个对角线为1的协方差矩阵,这需要先得到无偏的标准差: 我们先求得样本集的均值向量,均值向量的每个维度都是所有样本在该特征维度的值的平均 用样本集减去这个均值向量,得到一组中心化的数据$B$ 对这个集合求平方,然后求和,再除以$A-1$得到无偏方差 开方得到无偏标准差(Unbiased standard deviation)即样本标准差(Samples standard deviation) 。 为了避免样本标准差的某个维度为0,导致后续计算出错,可以给它加上一个极小的正数作为补偿。 用B矩阵除以标准差 得到规范化的矩阵X之后,我们计算 $X^TX$ 将得到的矩阵除以$A-1$,得到$F*F$的协方差矩阵 求解协方差矩阵的奇异值矩阵$S$和右奇异值$VT$向量矩阵,按从奇异值大到小,取对应的前M个向量,组成PCA转换矩阵 使用这个矩阵,对样本做矩阵乘法时,得到的就是降维后的结果向量。 实现 我最初做PCA算法的动机,来自于将 4096 维度的 ollama 嵌入向量降维到 2000 维以下——我的目标是256,那么在这个计算过程中,如果假设样本集数量为一万,计算过程中就会涉及好几次千万级的浮点数乘法。为了加速计算过程,使之可以优化到足以放到 PostgreSQL 内部使用,我使用AI框架 ggml 实现了一个 PCA 方法。 GGML 是一个 C 库,它支持 CUDA、MPX 等硬件加速方案,可以快速处理大规模的矩阵算法。 GGML 的tensor类型支持最多4个张量维度,PCA仅涉及矩阵和向量计算,只需要用到最多两位维度。所以这里仅使用GGML TENSOR的前两个维度。 在前述步骤中,基础的矩阵算法如乘法,加法等都有对应的 GGML... [Read More]
  • C/C++ 混合编程

    C/C++ 混合编程 这几天踩了一些坑,做个笔记。 两种语言,两个编译器 十多年前,我曾经是个职业的 CPP 程序员,但是那个时候我用 VC,这是一个高度自动化的 CPP 开发环境,它自动的做了太多的工作,以至于我甚至没有注意到自己的很多问题。 理论上,CPP是C的超集,使用 CPP 编译器可以自动的兼容 C 代码。这也导致了有时候我们其实不太注意自己到底在写C还是CPP。甚至很多构建工具允许我们用 CPP 编译器直接编译C 代码。 这在很多项目中是好的功能,不过我还是决定在 tensor dancer 项目中厘清这个问题,让混合编程的过程放到明面上来。 Meson 在默认情况下,使用 C 编译器编译 .c 文件,用 CPP 编译器编译 .cpp 文件。因为前面的理由,我没有将 c 编译器指定为 c++。 这样就暴露出一个问题,如果我在一个 c 程序中 include 一个CPP 头文件,它会递推到相关的 CPP 代码,这就会引发语法错误或符号找不到这样的错误。应对的方式是,定义一个 .h 文件 ,其中仅包含引用符合C标准的导出定义,例如dancer.h的内容是: [Read More]