博客

  • 探索大语言模型的最优架构:LLAMA-NAS的奇妙之旅

    引言

    在这个人工智能飞速发展的时代,大语言模型(LLMs)如同一位语言大师,解决了各种自然语言处理、复杂推理和情感分析任务。然而,这些“语言大师”往往需要极高的内存和计算资源,这让普通硬件平台望尘莫及。为了让更多人能使用LLMs,我们提出了一种基于LLaMA2-7B的高效神经架构搜索(NAS)方法,简称LLAMA-NAS。

    LLM的挑战和解决之道

    LLM如同巨兽

    大语言模型(LLMs)在处理自然语言和复杂推理任务上表现出了非凡的能力,但它们就像一头巨兽,消耗着大量的内存和计算资源。LLaMA2-7B,作为一款参数量达到7B的LLM,尽管功能强大,但其庞大的身躯让普通硬件平台难以承受。

    轻量化:从巨兽到精灵

    为了减轻LLMs的重量,我们提出了一种基于一击NAS(One-shot NAS)的方法。我们只对LLaMA2-7B进行一次微调,然后应用基于遗传算法的搜索,找到更小、更高效的网络架构。结果表明,在某些标准基准任务上,我们成功地将模型大小减少了1.5倍,并在几乎无损精度的情况下提升了1.3倍的吞吐量。

    方法:如何驯服LLMs

    InstaTune:一场架构的探险

    我们的优化方法借鉴了InstaTune,这是一种新颖的一击NAS方法。在微调LLaMA2-7B时,我们创建了一个超网络,并在微调阶段嵌入了NAS过程。这不仅节省了计算资源,还确保了子网络能够针对具体任务进行优化。

    我们使用了LINAS算法,这是一种结合NSGA-II搜索和网络性能预测器的方法,可以高效地识别Pareto最优的网络配置。通过在真实数据上迭代评估子网络,LINAS算法能够预测大量子网络的性能,并选择最有前途的进行进一步评估。

    搜索空间:在参数的海洋中航行

    在微调LLaMA2-7B后,我们定义了一组允许的参数值,并在搜索过程中使用这些参数。搜索空间包括了网络层数和每个MLP模块的中间大小。

    结果:轻量化的奇迹

    ARC:常识推理的挑战

    在AI2推理挑战(ARC)上,我们发现了几个比预训练的LLaMA2-7B更高效的子网络。例如,一个子网络在保持相同精度的情况下,体积减少了1.1倍,而另一个同等大小的子网络精度提升了1.9%。

    MMLU:多任务语言理解

    在大规模多任务语言理解(MMLU)任务中,我们的子网络不仅在模型大小上优于预训练的LLaMA2-7B,还在推理速度上有显著提升。例如,一个子网络在精度提升1.1%的同时,体积减少了1.5倍,速度提升了1.3倍。

    真相QA:真相的守护者

    在TruthfulQA任务上,我们的子网络表现更为出色。一个子网络在体积减少1.6倍的情况下,精度提升了3.6%。

    WinoGrande:常识推理的终极测试

    在WinoGrande任务上,我们的子网络也表现不俗。例如,一个子网络在保持相同精度的情况下,体积减少了1.1倍,而另一个同等大小的子网络精度提升了1.4%。

    总结:轻量化的未来

    我们的研究展示了一种高效的方法,通过一击NAS来减小和优化大语言模型的架构。我们的方法不仅在性能上优于剪枝和稀疏化技术,还能与量化技术结合,进一步减少模型的大小和复杂度。随着对大语言模型的兴趣不断增长,我们的工作为创建可在更便宜、更普及的硬件平台上使用的LLMs提供了一条可行之路。

    参考文献

    1. https://huggingface.co/meta-llama/Llama-2-7b
    2. LLM-Pruner: https://github.com/horseee/LLM-Pruner
    3. SliceGPT: https://github.com/microsoft/TransformerCompression

    希望这篇文章能够让您对LLAMA-NAS的方法和成果有一个清晰的了解,并在轻松愉快的阅读中学到新的知识。如果您有任何问题或需要进一步的信息,请随时联系我们。

  • LLAMA-NAS:让大语言模型不再“吃硬件”

    前言

    如果你觉得大语言模型(LLMs)像个贪吃的巨兽,那你就猜对了。这些能处理自然语言、复杂推理、情感分析等任务的模型,虽然能力非凡,但对内存和计算资源的“胃口”也惊人。以至于大部分硬件平台根本承受不起这顿“大餐”。为了让LLMs变得更“苗条”,我们提出了一种基于LLaMA2-7B的高效神经架构搜索方法——LLAMA-NAS。

    LLaMA2-7B的“减肥”计划

    一次性NAS:给模型做个“全身检查”

    我们的方法核心是一次性神经架构搜索(one-shot NAS),这个听起来就很酷对吧?具体来说,我们只对LLaMA2-7B模型进行一次微调,然后用遗传算法(genetic algorithm)来搜索更小、更高效的网络架构。结果显示,对于某些标准基准任务,预训练的LLaMA2-7B模型不仅“体型”庞大,而且“吃”得也多。通过我们的“减肥”计划,我们成功地将模型大小减少了1.5倍,处理速度提高了1.3倍,而准确度几乎没有损失。

    InstaTune:超级网络的“变形金刚”

    我们借鉴了InstaTune的方法,将NAS嵌入到微调阶段,使模型架构更具弹性,能够适应不同的任务、数据集和计算资源。在这过程中,我们并没有进行强教师或超级网络的知识蒸馏,主要是为了节省计算资源。

    搜索空间:模型参数的“百变金刚”

    在搜索过程中,我们使用了LINAS算法,这个名字听起来像某种神秘的武器。事实上,它确实很厉害,能够在多目标设置中优化模型大小和准确性。我们定义了一组允许的参数值,搜索空间包含了大约1.3 × 10^10种可能性。

    实验与结果

    AI2推理挑战

    首先,我们将方法应用于AI2推理挑战(ARC)任务,结果显示几个子网络架构在准确率和模型大小上都有明显提升。例如,一个子网络在准确率不变的情况下,模型大小减少了1.1倍。

    大规模多任务语言理解

    我们的方法在大规模多任务语言理解(MMLU)任务上也表现出色。多个子网络在准确率提升的同时,模型大小减少了1.5倍,处理速度提高了1.3倍。

    真诚QA和WinoGrande

    在真诚QA任务中,我们发现预训练的LLaMA2-7B模型明显过度参数化。通过我们的方法,找到的子网络在准确率提高3.6%的同时,模型大小减少了1.6倍。WinoGrande任务的结果也类似,我们的子网络在准确率不变的情况下,模型大小减少了1.1倍。

    比较与对比

    与剪枝和稀疏化技术的对比

    与LLM-Pruner和SliceGPT相比,我们的方法不仅在模型大小和准确率上更有优势,而且不需要额外的恢复微调步骤。

    量化:让模型“瘦上加瘦”

    我们还将INT8量化应用于搜索到的子网络,结果显示,量化后的子网络在准确率几乎不变的情况下,模型大小进一步减少。例如,一个子网络在量化后大小减少了2.5倍,准确率几乎没有损失。

    结论

    通过我们的LLAMA-NAS方法,我们不仅找到了更小、更高效的网络架构,还比剪枝和稀疏化技术更有效、更高效。而且,我们的方法不需要任何专用的软件内核或硬件,能够与其他量化方法无缝结合。随着对大语言模型的兴趣日益增加,我们的工作为自动创建能够在更便宜、更易获得的硬件平台上运行的网络提供了一条可行的道路。

    参考文献

    1. Anthony Sarah, Sharath Nittur Sridhar, Maciej Szankin, Sairam Sundaresan. “LLAMA-NAS: Efficient Neural Architecture Search for Large Language Models.”

    希望这篇文章能让你对我们的工作有更深入的了解,同时也希望你能像看完这篇文章一样开心。如果你对大语言模型的优化感兴趣,不妨试试我们的LLAMA-NAS方法,让你的模型也来次“瘦身”吧!

  • 不要忘记连接!用基于图的重排序提升RAG的表现

    认识一下RAG:文本生成的超级英雄

    Retrieval Augmented Generation,简称RAG,是一个能让大型语言模型(LLM)在回答问题时表现更佳的工具。RAG的工作原理是通过从现有文档中检索相关信息来为生成的文本提供背景支持。听起来是不是很厉害?但问题是,如果文档只提供部分信息或者与问题背景的连接不明显,那么RAG该怎么办?这篇文章就来回答这两个核心问题。

    G-RAG:图神经网络的魔力

    我们介绍一种基于图神经网络(GNN)的方法,叫做G-RAG。这个方法在RAG的检索器和阅读器之间引入了一个重排序器。G-RAG不仅考虑了文档之间的连接,还利用了语义信息(通过抽象意义表示图,AMR)来提供上下文感知的排序器。G-RAG不仅表现优异,还比最先进的方法更省计算资源。

    为什么重排序很重要?

    在开放领域问答(ODQA)中,RAG虽然能成功地检索到相关文档,但不能充分利用文档间的连接。这会导致模型忽视那些包含答案但与问题背景连接不明显的文档。通过重排序过程,我们能更有效地过滤检索到的文档,提高阅读过程的效果。

    现有方法的不足

    目前的重排序器虽然表现不错,但仍有一些问题。首先,大多数现有工作未能捕捉到不同检索文档之间的重要连接。其次,尽管AMR图提高了对复杂语义的理解,但将冗余的AMR信息集成到预训练语言模型中会导致过拟合和计算时间增加。最后,现有方法利用的预训练语言模型在快速发展的LLM时代显得不足。

    我们的解决方案

    为了应对这些挑战,我们提出了一种基于文档图的方法,每个节点代表一个文档,每条边代表两个文档之间存在共同概念。我们将不同文档之间的连接信息纳入边特征,并通过消息传递机制更新边特征。同时,我们在节点特征中加入了关键的AMR信息,避免了冗余信息的引入。

    实验结果

    我们在两个代表性的ODQA数据集上进行了实验:自然问题(NQ)和TriviaQA(TQA)。结果显示,基于图的策略(如GCN和G-RAG)在各种评估指标上表现出色。特别是G-RAG-RL模型,通过使用排序损失函数,进一步提升了识别正面文档的能力。

    结论与未来展望

    我们的G-RAG模型在现有ODQA方法中表现出色,通过利用文档之间的隐性连接和战略性地整合AMR信息,显著提高了识别有价值信息的能力。尽管预训练的LLM在重排序任务中的表现可能不尽如人意,但对其进行微调可能极大地提升RAG系统的表现。未来的研究方向包括设计更复杂的模型来更好地处理AMR信息,以及探索更高级的方法来解决LLM产生的排名分数中的平局问题。

    参考文献

    1. Wang, C., et al. (2023). “Graph as Tokens: Representing Text as Graphs for Neural Network Processing.” Retrieved from https://github.com/wangcunxiang/Graph-aS-Tokens/tree/main
    2. BERT: Bidirectional Encoder Representations from Transformers. (2019) Retrieved from https://arxiv.org/abs/1810.04805
    3. AMRBART: AMR Parsing with BART. (2020) Retrieved from https://arxiv.org/abs/2008.02759
    4. PaLM 2: A Next-Generation Language Model. (2022) Retrieved from https://arxiv.org/abs/2204.02311
  • 揭秘Caddy 2 + PHP-FPM 部署WordPress的卡顿谜团

    大家好,今天我将带您走进一个神秘的领域——Caddy 2 服务器与 PHP-FPM 部署的 WordPress 的卡顿现象。为什么我们辛辛苦苦搭建的网站会卡顿?让我们一探究竟。

    1. 初识Caddy 2与PHP-FPM

    首先,让我们简单介绍一下Caddy 2和PHP-FPM。Caddy 2 是一款现代化的开源Web服务器,因其自动HTTPS配置和简洁的配置文件赢得了广泛的好评。PHP-FPM(PHP FastCGI Process Manager)则是一个专为处理PHP请求优化的进程管理器,常用于提高网站性能。

    2. 卡顿现象的初步排查

    2.1 服务器资源不足

    当我们发现WordPress网站卡顿,首要怀疑的就是服务器资源不足。检查CPU使用率和内存占用情况是否过高。如果是的话,可能需要升级服务器配置。

    2.2 网络带宽问题

    网络带宽不足同样会造成网站卡顿。使用工具如 pingtraceroute 检查网络延迟和丢包率。如果网络状况不佳,可以尝试联系服务提供商解决。

    2.3 数据库性能

    WordPress的数据库性能也至关重要。使用 SHOW FULL PROCESSLIST; 命令检查MySQL数据库是否有慢查询,或者配置查询缓存来提高性能。

    3. 深入探讨Caddy 2与PHP-FPM的优化

    3.1 Caddy 2 的优化

    Caddy 2 默认的配置已经相当不错,但我们可以进一步优化:

    {
        auto_https off
        http_port 80
        https_port 443
    }
    
    example.com {
        root * /var/www/html
        php_fastcgi unix//run/php/php7.4-fpm.sock
        file_server
        encode gzip
    }
    • gzip压缩:启用gzip压缩可以减少传输数据量,提高加载速度。
    • 缓存:配置缓存以减少对服务器的压力。

    3.2 PHP-FPM 的优化

    PHP-FPM 的配置文件通常位于 /etc/php/7.4/fpm/pool.d/www.conf

    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 5
    pm.min_spare_servers = 5
    pm.max_spare_servers = 35
    pm.max_requests = 500
    • pm.max_children:设置能够处理的最大并发请求数。
    • pm.max_requests:设置每个子进程在重启前处理的最大请求数,避免内存泄漏。

    4. WordPress的优化

    4.1 插件管理

    尽量减少并优化插件,特别是那些影响性能的插件。使用插件如 Query Monitor 来监控性能瓶颈。

    4.2 缓存插件

    使用缓存插件如 W3 Total Cache 或 WP Super Cache,可以显著提高页面加载速度。

    4.3 图像优化

    图像通常是页面加载时间的主要因素之一。使用插件如 Smush 来优化图像大小。

    5. CDN加速

    将静态资源(如图片、CSS、JS)托管到CDN(内容分发网络)上,可以显著提高加载速度,减轻服务器负担。

    结论

    通过以上措施,我们可以有效解决Caddy 2 + PHP-FPM 部署的WordPress网站卡顿问题。当然,实际情况可能千差万别,您需要根据具体情况进行调整和优化。希望这篇文章对您有所帮助!


    参考文献:

  • GPT-4在文档理解中的应用

    介绍

    各位读者,你们是否曾经因为无法快速翻阅一大堆文档而感到头痛?别担心,我们的好朋友GPT-4来了!最近,Lukasz Borchmann 和他的团队在一篇名为《Notes on Applicability of GPT-4 to Document Understanding》的论文中详细探讨了GPT-4在文档理解领域的表现。让我们一起来看看这位AI大将是如何在文档中大显神通的吧!

    文档理解:不仅仅是文字

    文档理解不仅仅是读取文字,还包括理解文档的版式、图像和各种视觉线索。这就像是要你在一堆报纸中找到一条特定的新闻,不仅要看文字,还要注意标题、图片和排版。GPT-4 Vision Turbo在这方面表现优异,特别是当输入包括OCR识别的文字和文档图像时,效果更佳。

    实验结果:GPT-4的表现如何?

    Borchmann团队选择了四个数据集进行测试:DocVQA, InfographicsVQA, SlideVQA和DUDE。每个数据集都代表了不同类型的文档挑战。结果显示,TURBO V和TURBO V + OCR模型在结合视觉和文字信息时表现最佳,尤其是对文本密集型文档效果显著。

    例如,在DocVQA数据集上,TURBO V + OCR模型取得了87.4的高分,而纯文字模型的表现则稍显逊色。看来,GPT-4不仅能看懂文字,还能“看图说话”!

    错误分析:GPT-4的难题

    当然,GPT-4也不是完美无缺的。在一些情况下,模型对文档的理解会受到输入信息的影响。例如,当需要从图表或图像中提取信息时,OCR文字的辅助效果不如在纯文本情况下明显。这就像是让一个学霸去解一道偏题,即使聪明如他,也难免会栽跟头。

    另外,研究还发现,模型在处理长文档时表现有所下降,这可能是因为模型对长文本的上下文信息利用不充分。就像是让你读一本厚厚的小说,然后问你某个细节,你可能也会一时找不到答案吧!

    限制与未来展望

    这项研究也指出了一些限制。例如,目前的分析仅限于模型在特定数据集上的表现,而没有考虑数据隐私、成本、法律合规等实际应用中的重要因素。此外,研究还没有对模型进行微调,这意味着实际应用中可能会有更好的表现。

    未来的研究方向包括如何更好地安排文本顺序、提高模型的置信度校准、以及探索多问答形式的问答系统。看来,GPT-4还有很大的进步空间,值得我们期待!

    总结

    总的来说,GPT-4在文档理解中的表现令人印象深刻。虽然在某些方面还有改进的空间,但它已经展示了强大的潜力。特别是在结合OCR文字和文档图像后,GPT-4 Vision Turbo模型的表现尤为出色。这为我们在文档处理和自动化方面提供了新的可能性。

    各位读者,下次再面对堆积如山的文档时,不妨试试GPT-4吧!


    参考文献:

    1. Borchmann, L. (2023). Notes on Applicability of GPT-4 to Document Understanding.
    2. Mathew, M. et al. (2020). Document Visual Question Answering Challenge 2020. arXiv preprint arXiv:2008.08899.
    3. Mathew, M. et al. (2022). InfographicVQA. In Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision.
    4. OpenAI. (2023). GPT-4. https://openai.com/research/gpt-4.

    Q: 这篇论文试图解决什么问题?

    A: 这篇论文主要针对的是文档理解(Document Understanding)领域中GPT-4系列模型的适用性和性能问题。文档理解是指将文档转换为有意义的信息,通常涉及到集成布局、非文本元素和文本样式所代表的线索。论文中提到,尽管文本只能模型在文档理解任务上难以取得令人满意的结果,但是GPT-4 Vision Turbo模型在输入中同时提供外部OCR引擎识别的文本和文档图像时表现良好。

    论文试图解决的具体问题包括:

    1. 评估GPT-4家族模型在文档理解领域的性能:作者对所有公开可用的GPT-4系列模型进行了评估,以了解它们在文档理解任务上的表现,并与专门为此目的开发的模型进行比较。
    2. 探索GPT-4模型在文档视觉问题回答(Document Visual Question Answering)上的表现:这是文档理解任务中的一种,作者选择这一任务进行评估,因为它既适合基于LLM的聊天助手,又可以通过自然语言提问或指定指令来请求文档中的每一条信息。
    3. 解决GPT-4模型在商业API中可实现的结果与报道结果之间的差异:作者提到,尽管GPT-4模型的新闻发布提到了在两个文档VQA数据集上的分数,但具体细节仍然未知,而且不清楚这些结果是否可以通过商业API实现。
    4. 分析GPT-4模型在处理长文档时的性能下降问题:论文中提到,对于长文档,GPT-4模型的性能显着下降。
    5. 探讨数据污染问题:作者还研究了GPT-4模型训练或测试数据集是否可能受到污染,这可能会影响模型性能的评估。
    6. 提出改进建议和未来研究方向:在论文的最后部分,作者提出了一些可能的改进领域,并对未来的研究提出了建议。

    总的来说,这篇论文试图提供一个详细的技术报告和可复现的评估程序,以填补现有知识与GPT-4模型在文档理解任务上性能之间的差距。

    Q: 有哪些相关研究?

    A: 论文中提到了多个与文档理解(Document Understanding)和视觉问题回答(Visual Question Answering, VQA)相关的研究和数据集。以下是一些主要的相关研究和数据集:

    1. DocVQA (Mathew et al., 2020): 这是一个文档视觉问题回答的数据集,专注于文本密集型文档。
    2. InfographicsVQA (Mathew et al., 2022): 专注于信息图表的视觉问题回答数据集。
    3. SlideVQA (Tanaka et al., 2023): 针对幻灯片文档的视觉问题回答数据集。
    4. DUDE (Van Landeghem et al., 2023): 文档理解数据集和评估,包含多种类型的问题和答案。
    5. Qwen-VL (Bai et al., 2023): 一个多模态视觉语言模型,用于理解、定位、文本阅读等任务。
    6. InternVL (Chen et al., 2023, 2024): 用于通用视觉语言任务的视觉基础模型。
    7. InstructDr (Tanaka et al., 2024): 针对文档理解的指令化数据集。
    8. GRAM (Blau et al., 2024): 用于多页文档视觉问题回答的全局推理模型。
    9. Tesseract OCR: 一个开源的光学字符识别引擎。
    10. Azure Cognitive Services: 微软提供的一系列认知服务,包括OCR功能。
    11. Amazon Textract: 亚马逊提供的文档文本检测和分析服务。

    这些研究和数据集为文档理解领域提供了丰富的资源,使得研究人员能够开发和评估处理文档图像和文本的模型。论文中对这些资源进行了评估和比较,以确定GPT-4系列模型在文档理解任务上的性能。

    Q: 论文如何解决这个问题?

    A: 论文通过以下步骤和方法解决文档理解领域中GPT-4模型的性能评估问题:

    1. 模型评估:作者对所有公开可用的GPT-4家族模型进行了评估,特别是关注了文档视觉问题回答(Document Visual Question Answering)这一子领域。
    2. 数据集选择:选择了DocVQA、InfographicsVQA、SlideVQA和DUDE等数据集,这些数据集覆盖了文档类型的全谱系,包括文本密集型和视觉密集型文档,以及多页文档。
    3. 实验设计:作者设计了一系列实验,包括最佳提示(prompt)的选择、图像分辨率的优化以及OCR(光学字符识别)引擎的比较。
    4. 性能比较:通过比较不同模型版本(如TURBO V、TURBO V + OCR、8K + OCR、32K + OCR等)在不同数据集上的性能,来评估它们在文档理解任务上的表现。
    5. 错误分析:利用数据集的诊断类别和元数据来分析模型性能,特别是根据输入和证据特征进行分析。
    6. 数据污染分析:研究了训练或测试数据集是否可能在GPT-4模型的训练数据中,从而影响性能评估的准确性。
    7. 局限性讨论:作者讨论了分析的局限性,如仅关注模型性能、数据集选择的合理性、未进行微调(finetuning)、OCR引擎的影响等。
    8. 未来研究方向:提出了未来研究的潜在领域,包括文本布局的重要性、置信度校准、多QA问题的处理等。
    9. 详细技术报告和复现性:与以往不公开的设置不同,作者提供了详细的技术报告和可复现的评估程序,确保了研究的透明度和可靠性。

    通过这些步骤,论文不仅评估了GPT-4模型在文档理解任务上的性能,还提供了深入的分析和对未来研究方向的建议。

    Q: 论文做了哪些实验?

    A: 论文中进行了一系列实验来评估GPT-4家族模型在文档理解领域的性能。以下是实验的主要步骤和内容:

    1. 数据集选择:选择了DocVQA、InfographicsVQA、SlideVQA和DUDE等数据集,以覆盖不同类型和特点的文档。
    2. 最佳提示(Prompt)确定:在验证集上对不同的提示进行了优化,以确定最佳的提示组合。这些提示旨在提高模型对问题的回答质量。
    3. 图像分辨率优化:研究了不同图像分辨率对模型性能的影响,以确定最佳的输入图像大小。
    4. OCR引擎比较:比较了Tesseract、Azure Cognitive Services和Amazon Textract等不同的OCR引擎,以确定哪个引擎在文本识别方面表现最佳。
    5. 模型版本比较:评估了不同版本的GPT-4模型,包括TURBO V、TURBO V + OCR、8K + OCR和32K + OCR等,以了解它们在文档理解任务上的表现。
    6. 错误分析:利用数据集的诊断类别和元数据,分析了模型在不同类型的输入和证据特征下的性能。
    7. 证据位置分析:研究了模型性能如何随着请求信息在文档中的位置而变化,以了解模型是否存在对输入文档开始或结束部分的偏好。
    8. 答案类型分析:分析了模型在处理不同类型的答案(如列表答案和不可回答问题)时的性能。
    9. 引导指令污染分析:通过在提示中加入特定数据集的名称,来检查模型性能是否因数据集名称的存在而受到影响,从而评估数据污染的可能性。
    10. 性能提升分析:研究了通过提供外部OCR引擎识别的文本作为输入的一部分,对GPT-4 Vision模型性能的影响。

    这些实验的目的是为了全面评估GPT-4模型在文档理解任务上的性能,并探索提高性能的不同方法和因素。通过这些实验,作者能够提供关于GPT-4模型在文档理解领域适用性的深入见解。

    Q: 有什么可以进一步探索的点?

    A: 根据论文内容,以下是一些可以进一步探索的点:

    1. 文本布局的重要性:研究不同OCR设置如何影响文本阅读顺序和完整性的保持,以及空间布局的理解。
    2. 置信度校准:评估和改进文档理解系统中置信度分数的校准,这对于业务流程自动化尤为重要。
    3. 多QA问题处理:探索如何同时从单个文档中提取多个值,这可能提高成本效率并潜在地提高答案质量。
    4. 不同输入文本表示和排列的影响:研究不同的文本输入表示和排列方式对模型性能的影响,特别是对于纯文本大型语言模型(LLMs)。
    5. 数据集选择的多样性:考虑不同的数据集选择对模型性能评估的影响,以及如何通过多样化的数据集来提高模型的泛化能力。
    6. 微调(Finetuning)的影响:研究在特定数据集上微调大型语言模型对性能的潜在提升。
    7. 零样本学习(Zero-shot learning)的优化:探索不同的提示(prompt)策略,以提高零样本性能。
    8. OCR质量对模型性能的影响:研究OCR引擎的不同输出如何影响模型的性能,并寻找提高OCR质量的方法。
    9. 第三方API的依赖性:研究如何减少对第三方API的依赖,以及如何确保模型在实际部署中的稳定性和一致性。
    10. 模型的“理解”能力:深入研究模型在文档处理中的“理解”能力,以及如何评估和提高这种能力。
    11. 模型的偏见和公平性:评估模型可能存在的偏见,并探索减少这些偏见的方法,以确保模型的公平性。
    12. 模型的可解释性和透明度:提高模型的可解释性,以便更好地理解其决策过程,并增加用户对模型输出的信任。

    这些探索点可以帮助研究者和开发者更好地理解和改进大型语言模型在文档理解任务上的性能,以及在实际应用中的可靠性和有效性。

    Q: 总结一下论文的主要内容

    A: 这篇论文的主要内容可以总结如下:

    1. 研究背景:论文探讨了GPT-4家族模型在文档理解领域的适用性,特别是在需要理解文本的空间布局和视觉线索的情况下。
    2. 文档理解定义:文档理解是指将文档转换成有意义的信息,通常需要集成布局、非文本元素和文本样式的线索。
    3. GPT-4家族模型:论文评估了不同版本的GPT-4模型,包括文本模型和能够处理图像输入的模型。
    4. 实验设计:作者选择了DocVQA、InfographicsVQA、SlideVQA和DUDE等数据集进行评估,并在验证集上对提示、图像分辨率和OCR引擎进行了优化。
    5. 性能评估:通过比较不同模型在各个数据集上的表现,发现结合视觉和文本信息的模型(如TURBO V + OCR)性能更优。
    6. 错误分析:分析了模型性能与输入文档表示信息的方式之间的关系,以及模型在不同证据位置和答案类型下的表现。
    7. 数据污染分析:探讨了训练或测试数据集可能在GPT-4模型训练数据中的情况,以及这可能对性能评估产生的影响。
    8. 局限性:论文讨论了研究的局限性,包括仅关注模型性能、数据集选择的合理性、未进行微调、OCR引擎的影响等。
    9. 未来研究方向:提出了未来研究的潜在领域,如文本布局的重要性、置信度校准、多QA问题处理等。
    10. 详细技术报告:与以往不公开的设置不同,作者提供了详细的技术报告和可复现的评估程序,确保了研究的透明度和可靠性。

    总的来说,这篇论文提供了对GPT-4家族模型在文档理解任务上性能的全面评估,并探讨了影响性能的多种因素,同时提出了未来研究的方向。

  • “闭门造车”之多模态模型方案浅谈

    前言

    大家好,今天我要和大家聊聊一个即便我闭门造车也能侃侃而谈的热门话题——多模态模型。近期Google的Gemini 1.5和OpenAI的Sora再次点燃了大家对多模态技术的热情。虽然我没有亲身实践过这些大模型,但凭借一些文本生成和图像生成的经验,我依然可以带大家一探究竟。

    问题背景

    多模态模型,简而言之,就是能同时处理图文混合的模型。有人可能会想,这不就是烧钱堆显卡,然后用Transformer“一把梭”搞定吗?其实没那么简单。文本生成一直有明确的方向——语言模型。而图像生成则没有这样清晰的路线,VAE、GAN、Flow、Diffusion等方法各显神通,原因就在于图像生成需要对连续变量进行概率建模,这比文本生成复杂得多。

    离散之路

    既然连续难搞,那能不能把图像离散化,套用文本生成的框架呢?答案是可以的,这也是目前的主流思路。图像本质上是离散的,比如一幅$n \times n$大小的RGB图像,就是$3n^2$个0~255的整数。我们可以通过VQ-VAE或者VQ-GAN这样的“图像Tokenizer”进行离散化,然后用文本生成的方式处理这些离散的图像Token。

    压缩损失

    虽然听起来很美好,但图像Tokenizer有一个大问题——信息损失。为了提高生成速度,通常会对图像进行高度压缩,这导致图像细节严重缺失。参考SEED的重构效果,虽然整体语义保持,但细节完全不同。无损压缩是理想状态,但目前的技术还达不到这个水平。

    扩散模型

    面对信息损失的问题,如果限定无损压缩,那么扩散模型是一个不错的选择。扩散模型通过将标准高斯分布映射为目标分布,有足够的熵源来保证生成效果。相比之下,Flow模型虽然设计上可逆,但效果上限不如扩散模型。因此,扩散模型成为了图像生成的首选。

    Patch输入

    一个大胆的想法是直接以原始图像的Patch作为输入,用Transformer进行处理。这样可以避免特征间的孤立问题。实验表明,这种做法是可行的,虽然训练步数较多,但在多模态大模型训练中的步数本身就很大,所以这不算大问题。

    文章小结

    本文介绍了一种多模态模型的设计构思,即直接以原始图像的Patch作为图像输入,文本部分常规预测下一个Token,图像部分用加噪图像重构原图。这种组合能够以最保真的方式实现多模态生成。虽然这只是我闭门造车的一些想法,但希望能给大家带来一些启发。

    参考文献

    苏剑林. (Feb. 21, 2024). 《“闭门造车”之多模态模型方案浅谈》[Blog post]. Retrieved from 科学空间


    希望大家喜欢这篇文章,欢迎分享和讨论!

  • 以蒸馏的名义:“从去噪自编码器到生成模型”重现江湖

    前言

    今天我们要聊的,是一篇名为《Score identity Distillation: Exponentially Fast Distillation of Pretrained Diffusion Models for One-Step Generation》的论文。顾名思义,这篇论文探讨了如何更快、更好地蒸馏扩散模型。即便你对蒸馏一无所知,看到这里也不必担心,咱们一步步来。

    蒸馏模型:从繁到简的艺术

    常规蒸馏步骤

    蒸馏的常规步骤是什么呢?简单来说,就是随机采样大量输入,然后用扩散模型生成相应的输出,用这些输入输出作为训练数据对,来监督训练一个新模型。但是,这种方法需要教师模型迭代多次(比如1000次)才能生成高质量输出,费时费力,还容易造成效果损失。有没有更高效的方法呢?

    Score Identity Distillation(SiD)

    这篇论文提出了一种名为“Score identity Distillation(SiD)”的方法。虽然名字高大上,但其实思路很简单:它利用了一些恒等式来设计和推导整个框架。不过,这些恒等式本身并不新,名字只是为了显得高端而已。

    重现江湖:从去噪自编码器到生成模型

    初级形式

    假设我们有一个训练好的教师扩散模型,它需要多步采样才能生成高质量图片。我们的目标是训练一个单步采样的学生模型,即一个类似GAN的生成器,只需输入噪声就能生成图像。如果我们有大量的输入输出对,那么直接监督训练就可以了,但如果没有呢?

    SiD采用了一个看似绕但很聪明的思路:如果学生模型生成的数据分布和目标分布很相似,那么用学生模型生成的数据集去训练一个扩散模型,它也应该和教师模型相似。

    点睛之笔

    谈到GAN,有些人可能会“闻之色变”,因为它们容易训崩。但SiD提出了一个有效的解决方案:通过恒等变换,尽量消除优化目标对某些变量的依赖,使得训练更加稳定。

    恒等变换

    具体来看,SiD通过一系列恒等变换,将优化目标简化为一个更易处理的形式。这些变换利用了概率密度定义和贝叶斯公式,使得训练过程更高效。

    实践中的挑战与解决方案

    训练中的坑

    虽然理论上SiD的方法看起来很美,但在实际操作中仍然存在一些挑战。例如,如何在不牺牲效果的前提下减少显存需求。论文提出了未来可以尝试对预训练模型加LoRA来进一步节省显存。

    延伸思考

    SiD的方法虽然已经很完善,但仍有改进空间。比如,是否可以进一步简化恒等变换,或者引入新的优化策略来提高训练效率。

    文章小结

    总的来说,SiD通过一系列精妙的恒等变换和优化策略,成功地将复杂的多步扩散模型蒸馏为单步生成模型。这不仅提高了生成效率,还减少了对训练数据和计算资源的需求。未来,随着更多改进和优化的引入,SiD有望在更加广泛的应用场景中展现其价值。


    参考文献

    苏剑林. (May. 01, 2024). 《以蒸馏的名义:“从去噪自编码器到生成模型”重现江湖 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/10085

  • 数字版“疯牛病”:生成模型的自噬之路

    引言

    众所周知,不管是文本还是视觉领域,各种生成模型正在以无法阻挡的势头“肆虐”互联网。虽然大家都明白,实现真正的通用人工智能(AGI)还有很长的路要走,但这并不妨碍人们越来越频繁地利用生成模型来创作和分享内容。君不见,很多网络文章已经配上了Stable Diffusion模型生成的插图;君不见,很多新闻风格已经越来越显现出ChatGPT的影子。看似无害的这种趋势,正悄然引发了一个问题:我们是否应该对互联网上充斥的生成模型数据保持警惕?

    近期发表的论文《Self-Consuming Generative Models Go MAD》揭示了一种令人担忧的可能性,那就是生成模型正在互联网上的无节制扩张,可能会导致一场数字版的“疯牛病”疫情。本文将带您一起学习这篇论文,探讨其可能带来的影响。

    “食自己”

    一方面,人们使用生成模型的频率越来越高,将会导致互联网上由生成模型创作的内容越来越多;另一方面,生成模型也在更新迭代,其所用的数据也是从互联网爬取的。可以想像,后续的训练集中由生成模型创作的部分占比将会越来越高。换句话说,后面的每一代模型迭代时可能都没有足够多的新鲜数据,纯粹是用自己生产的数据来训练,用广东话说就是“食自己”,这将导致模型的质量或者多样性越来越差,原论文称之为“模型自噬紊乱(Model Autophagy Disorder,MAD)”。

    无独有偶,生物学上也曾出现了类似的例子。牛是草食动物,然而,一些畜牧业者为了增强其营养供应,将其他牛的残骸(包括大脑)粉碎并混入饲料中。这在当时看起来是一个机智的做法,但未曾想到最后导致了“疯牛症”的出现和大规模传播。这一事例说明,长期的“食自己”可能会导致有害因素累积在生物体内,一旦达到一定程度,甚至可能触发灾难性的疾病。

    因此,我们同样需要反思生成模型的“肆虐”是否会在互联网上引发另一场“疯牛症”——这不仅可能导致信息的同质化,使得各种内容开始变得千篇一律,缺乏原创性和多样性,还有可能引发一系列无法预见的问题。

    降多样性

    可能有读者会产生疑问:生成模型不就是对真实数据分布的模拟吗?即便连续地使用生成模型的数据进行迭代训练,应该只是在重复呈现真实的数据分布,怎么会导致多样性的丧失呢?

    这其中的原因是多方面的。首先,训练生成模型的数据往往并非直接取自真实分布,而是经过人为的加工处理,比如去噪、规范化和对齐。经过加工后,训练集就已经丧失了部分多样性。例如,我们之所以能观察到很多新闻报道或知乎回答都有一股ChatGPT的味道,并非是因为内容本身,而是因为它们的格式与ChatGPT的相似性,这就说明ChatGPT的训练数据和输出结果的风格都比较明显且局限。再比如,为了降低图像生成模型的训练难度,我们通常需要对图像进行对齐处理,如在训练人脸生成模型时,常常需要将所有人脸的眼睛对齐到同一位置,这些操作也导致了多样性的丧失。

    此外,还有一个很关键的因素是,由于生成模型本身或者训练技巧等限制,每个生成模型都无法做到完美,此时我们通常会主动地引入一些牺牲多样性来提高生成质量的技巧。比如,对于GAN、Flow等生成模型,我们会选择降低采样噪声的方差,以获得质量更高的生成结果,这就是所谓的截断技巧或退火技巧。另外,如《生成扩散模型漫谈(九):条件控制生成结果》所述,在扩散模型中我们通常引入条件信息以控制输出结果,不管是Classifier-Guidance还是Classifier-Free方案,额外条件的引入也会限制生成结果的多样性。总而言之,在生成模型不尽完美时,我们在平衡质量与多样性过程中,就主动地放弃了部分多样性。

    正态分布:简单却深刻的例子

    为了更深刻地认识到这种现象,我们接下来将探讨一些具体的例子。作为开始,我们首先考虑的是正态分布,因为它足够简单,所以求解和分析都更加清晰。但后面我们可以观察到,结果已经足够有代表性了。

    假设真实分布是多元正态分布 N(μ0, Σ0),我们用来建模的分布也是正态分布 N(μ, Σ),那么训练模型的过程,就是从训练集里边估计均值向量 μ 和协方差矩阵 Σ。接下来我们假设每一代生成模型训练时,都只用到上一代生成模型创作的数据,这是比较极端的假设,但不可否认当生成模型进一步普及时,这个假设越来越接近成立。

    在这些假设下,我们从 t-1 代生成模型 N(μt-1, Σt-1) 中采样 n 个样本 x(1)t-1, x(2)t-1,⋯, x(n)t-1,来训练第 t 代的生成模型:

    μt = 1/n ∑_{i=1}^n x(i)t-1
    Σt = 1/(n-1) ∑_{i=1}^n (x(i)t-1 - μt)(x(i)t-1 - μt)^⊤

    注意,如果加上截断技巧,那么第 t 代的生成模型就是 N(μt, λΣt),其中 λ∈(0,1)。于是可以想象,每一代的方差(多样性)都将以 λ 的比率衰减下去,最后变成零(完全丧失多样性)。如果不使用截断技巧(即 λ=1)是不是就没事了?并不是。根据定义 μt = 1/n ∑_{i=1}^n x(i)t-1,由于 x(i)t-1 都是随机采样得到的,所以 μt 也是一个随机变量,根据正态分布的叠加性,它实际上服从:

    μt ∼ N(μt-1, 1/n Σt-1) ⇒ μt ∼ N(μ0, t/n Σ0)

    可以预见,当 t 足够大时,μt 本身就会明显偏离 μ0,这对应的是质量的崩溃,而不单单是多样性的降低。

    总的来说,截断技巧的引入,会大大加速多样性的丧失速度,而即便没有截断技巧,在长期有限样本的迭代训练中,生成分布也有可能明显偏离原始的真实分布。注意,正态分布这个例子所做的假设已经比一般的生成模型要弱得多,至少它的拟合能力是保证足够的,但这依然不可避免多样性衰减或者质量崩溃,而对于真实世界的数据和能力有限的生成模型来说,理论上只会更加糟糕。

    生成模型的实验验证

    对于实际的生成模型,理论分析难以进行,所以只能通过实验来探索结果了。原论文做了非常丰富的实验,结果基本上跟正态分布的结论一致,即如果加入截断技巧的话,多样性将会迅速丧失,即使没有截断技巧,经过反复迭代后的模型依然会不可避免地出现一些偏离。

    小结

    本文探讨了当各种生成模型大规模“肆虐”互联网时可能出现的后果。在生成模型反复用自己生成的数据进行更新迭代时,可能会导致信息严重同质化、丧失多样性的问题,类似于曾经因“牛吃牛”而出现的“疯牛病”。原论文通过理论分析和实验验证,揭示了生成模型在长期迭代中可能出现的“模型自噬紊乱(Model Autophagy Disorder,MAD)”现象。

    尽管生成模型为我们带来了许多便利和创新,但我们也需要警惕其潜在的风险。未来,我们或许需要更智能的数据筛选机制和更丰富的数据源来避免这种“食自己”的现象,从而确保生成模型的多样性和质量。

    参考文献

    希望本文能为您带来一些启发,帮助您更好地理解生成模型的潜在风险。如果您有任何疑问或建议,欢迎留言交流!


    生成模型的未来,或许不只是技术的进步,更是我们对其使用方式的深思熟虑。让我们共同期待一个更加多样化和创新的数字世界!

  • 梯度流:从数学到魔法的奇幻旅程

    导言:梯度流的神奇世界

    在数学和机器学习的广袤世界中,有一个神秘的概念被称为“梯度流(Gradient Flow)”。如果你对梯度下降法有一定了解,那么你应该知道它是寻找函数最小值的强大工具。而梯度流,则是将这个寻找最小值的过程中的各个点连接起来,形成一条随时间变化的轨迹。本文将带你深入探讨这个奇妙的概念,并进一步扩展到概率空间,揭示出“Wasserstein梯度流”的神秘面纱。

    梯度下降:从山顶到山谷的滑梯

    1.1 梯度下降的基本原理

    假设我们站在一座山顶,想要找到最低谷的那一点。为了实现这个目标,我们可以使用梯度下降法。这个方法的核心在于,我们总是沿着当前点的负梯度方向前进,因为负梯度方向是局部下降最快的方向。具体的迭代公式如下:

    xt+1 = xt − α∇xf(xt)

    在这个公式中,xt表示当前的位置,α是学习率,∇xf(xt)是函数在xt点的梯度。如果函数f(x)是凸的,梯度下降通常能够找到最小值。即使函数不是凸的,梯度下降也能让我们接近一个极小值点。

    1.2 梯度流的定义

    如果我们将学习率α记作Δt,并考虑当Δt趋近于0时的极限情况,那么梯度下降的迭代公式将变为一个常微分方程(ODE):

    dxt/dt = −∇xf(xt)

    求解这个ODE得到的轨迹,就是所谓的“梯度流”。换句话说,梯度流是梯度下降在寻找最小值过程中的轨迹。

    最速方向:为什么要选择梯度下降

    2.1 局部最快下降方向

    为什么梯度下降法如此受欢迎?一个常见的说法是“梯度的负方向是局部下降最快的方向”。这个说法虽然没错,但有些不够严谨。因为“最快”涉及到定量比较,只有先确定比较的指标,才能确定“最”的结果。

    2.2 约束优化视角

    在欧氏空间中,梯度的负方向是局部下降最快的方向。然而,如果我们换一个模长的定义,或者换一个约束条件,结果可能就会不同。因此,从优化的角度来看,梯度下降法对应的优化目标是:

    xt+1 = argminx ||x - xt||^2 / (2α) + f(x)

    这意味着我们将约束条件转化为一个惩罚项,从而简化了优化过程。

    泛函与概率空间:从函数到密度函数

    3.1 泛函的引入

    普通的多元函数输入一个向量,输出一个标量。而泛函则是输入一个函数,输出一个标量。例如,定积分运算:

    I[f] = ∫ba f(x) dx

    在这里,I[f]就是一个泛函。我们将关注的泛函定义域为全体概率密度函数的集合,即研究输入一个概率密度、输出一个标量的泛函。

    3.2 Wasserstein梯度流的引入

    假设我们有一个泛函F[q],想要计算它的最小值。模仿梯度下降的思路,我们可以沿着它的负方向进行迭代。对于概率分布来说,性态比较好的距离是Wasserstein距离。我们可以将欧氏距离替换为Wasserstein距离,最终得到:

    ∂qt(x)/∂t = ∇x ⋅ (qt(x) ∇x δF[qt(x)] / δqt(x))

    这就是“Wasserstein梯度流”,其中δF[q]/δqF[q]的变分导数。

    应用与示例:从理论到实践

    4.1 f散度的应用

    例如,对于f散度,我们可以得到:

    ∂qt(x)/∂t = ∇x ⋅ (qt(x) ∇x(f(rt(x)) − rt(x) f'(rt(x))))

    其中,rt(x) = p(x) / qt(x)。这一公式可以帮助我们通过ODE从分布qt中采样。

    4.2 逆KL散度的应用

    另一个简单的例子是逆KL散度,当我们使用负对数作为函数f时,得到:

    ∂qt(x)/∂t = -∇x ⋅ (qt(x) ∇x log(p(x) / qt(x)))

    这正好是一个Fokker-Planck方程,对应的随机微分方程(SDE)为:

    dx = ∇x log(p(x)) dt + √2 dw

    这意味着,如果我们知道log(p(x)),那么就可以用上式实现从p(x)中采样。

    文章小结

    本文介绍了从梯度下降法到梯度流的概念,并进一步扩展到概率空间,引入了Wasserstein梯度流的概念。我们讨论了这些概念与连续性方程、Fokker-Planck方程和ODE/SDE采样之间的联系。通过这些讨论,我们不仅揭示了数学优化中的一些核心原理,还展示了这些原理在概率密度函数优化中的应用。希望这次奇幻旅程让你对梯度流有了更深的理解!


    如果你对优化算法和深度学习有更多兴趣,可以参考以下资源:

    • 《从动力学角度看优化算法(一):从SGD到动量加速》
    • 《从动力学角度看优化算法(三):一个更整体的视角》
    • 《从Wasserstein距离、对偶理论到WGAN》

    愿你在数学与机器学习的世界中探索得愉快,发现更多的奇妙与乐趣!

  • 梯度流与Wasserstein梯度流:从山顶滑雪到概率风景线

    大家好!今天我们要聊一聊一个有趣的概念,叫做“梯度流(Gradient Flow)”。别紧张,这不是物理课,而是数学和机器学习的世界。简单来说,梯度流就是我们用梯度下降法寻找最小值的过程中,每个点连成的一条轨迹,就像你在山顶滑雪,每个滑下的轨迹都是梯度流。在这篇文章的后半部分,我们将探讨如何将梯度流的概念扩展到概率空间,变成“Wasserstein梯度流”。这将为我们理解连续性方程和Fokker-Planck方程等内容提供一个全新的视角。

    梯度下降:从山顶到山谷

    假设我们要寻找一个光滑函数的最小值。常见的做法是梯度下降(Gradient Descent),就像从山顶滑雪一样,沿着山坡的斜度(即梯度)往下滑。如果这个山坡是光滑且凹的(数学术语叫凸的),那么你通常能顺利滑到山谷;如果山坡崎岖不平,你可能会卡在某个小山谷里,但能下滑到某个低谷也算不错了。

    如果我们把滑雪的步长记为“Δt”,滑雪的轨迹记为“xt”,当步长趋近于0时,这个滑雪过程就变成了一条连续的轨迹,这条轨迹就是所谓的“梯度流”。这意味着,只要你沿着梯度方向滑动,即使步长很小,你总能往让目标函数值变小的方向前进。

    最速方向:滑雪的最佳路线

    为什么要用梯度下降?一个主流说法是“梯度的负方向是局部下降最快的方向”。这就好比在滑雪时,你选择坡度最大、速度最快的路线。然而,这个说法有点不严谨,因为没说明前提条件——在欧氏空间中,梯度的负方向才是局部下降最快的方向。如果换一种度量方式,结果可能就不一样了。

    优化视角:从滑雪到滑翔机

    我们还可以将梯度下降的目标推广到更复杂的优化场景中。比如,自然梯度下降(Natural Gradient Descent)使用的是KL散度作为正则项。想象一下,你不仅要从山顶滑到山谷,还要避开雪崩和岩石,这就需要更复杂的导航技巧。通过这种方式,我们可以得到更精确的轨迹。

    泛函入门:从滑雪到概率风景线

    “泛函”这个词听起来有点吓人,但其实它只是输入一个函数,输出一个标量的运算,比如定积分。我们可以将这个概念推广到概率密度函数的集合中,也就是说,输入一个概率密度函数,输出一个标量。

    概率之流:从滑雪到漂流

    假如我们有一个泛函F[q],想要计算它的最小值,那么可以模仿梯度下降的思路,沿着它的负方向进行迭代。在概率空间中,我们可以使用Wasserstein距离来替代欧氏距离,这样就得到了“Wasserstein梯度流”。

    尽管求解这些数学公式可能有点复杂,但最终的结果是,我们可以通过这种方法来理解和求解连续性方程和Fokker-Planck方程。这就像是从滑雪转换成漂流,通过水流的方向来找到最优的路径。

    总结:从山顶滑雪到概率漂流

    今天,我们探讨了梯度流和Wasserstein梯度流的概念,从简单的梯度下降到复杂的概率空间优化。通过这种视角,我们不仅更好地理解了连续性方程和Fokker-Planck方程,还为未来的研究提供了新的思路和方向。

    希望通过这篇文章,大家不仅学到了知识,还能感受到数学和机器学习的奇妙之处。就像滑雪和漂流一样,掌握了技巧,你就能在这片知识的海洋中自由穿梭。下次再见!

  • 朴素贝叶斯与注意力机制:一场“心有灵犀”的邂逅

    嘿,朋友们!今天我们要聊的可是AI界的两位“大明星”——朴素贝叶斯(Naive Bayes)和注意力机制(Attention)。这两位一个朴实无华,一个炫酷吊炸天,但你知道吗?它们之间其实有很多“不可告人”的秘密!

    朴素贝叶斯:老实人的自白

    先来认识一下朴素贝叶斯,这位老兄可是AI界的“老黄牛”,简简单单,踏踏实实。他的工作原理就像是你在餐厅点菜,完全按照菜单上的推荐组合来点。每道菜都有它自己的独立评分,然后你根据这些评分来决定哪道菜最可能是你喜欢的。

    一般化的朴素贝叶斯:变身超级英雄

    不过,老实人的日子久了,朴素贝叶斯也想来点儿新花样,于是他决定进行一次“大变身”。他学会了一种叫做“加权平均”的技术,不再是每道菜的评分都一样,而是根据餐厅老板的推荐来调整每道菜的权重。这样一来,他的推荐就显得更加聪明了。

    注意力机制:时尚界的弄潮儿

    接下来登场的是注意力机制,这位可是AI界的新锐潮人。他的理念是“要注意到每一个细节”。在他看来,每个词对当前词的影响力是不一样的,有的词可能只是打酱油的,有的词则是重头戏。于是,他发明了“注意力分数”,用来衡量每个词的重要性,然后根据这些分数进行加权平均。

    当朴素贝叶斯遇上注意力机制

    这时,朴素贝叶斯和注意力机制这两个大明星终于碰面了。朴素贝叶斯惊讶地发现,这个炫酷的注意力机制,竟然和自己有那么多相似之处!原来,注意力机制也是一种广义的朴素贝叶斯,只不过是通过更加灵活的加权平均,来捕捉词与词之间的复杂关系。

    深度模型:层叠与残差的魔法

    不过,单层的朴素贝叶斯和注意力机制能力有限,为了让自己变得更强大,他们决定学习一种叫做“层叠”的魔法。简单来说,就是把多个简单的模型叠加起来,形成一个超级复杂的模型。

    在这个过程中,他们还学会了一种叫做“残差连接”的技巧。这就像是你在写文章的时候,既要保持文章的连贯性,又要突出重点。通过这种方式,模型在捕捉复杂关系的同时,也能保留一些简单的、直接的关系。

    总结:一场“心有灵犀”的邂逅

    今天,我们见证了朴素贝叶斯与注意力机制这两位大明星的“心有灵犀”时刻。通过这种视角,我们不仅更好地理解了注意力机制中的层叠与残差,还为未来的研究提供了新的思路和方向。

    所以,朋友们,如果你对AI技术感兴趣,不妨多了解一下朴素贝叶斯和注意力机制这两位大明星。他们之间的“化学反应”一定会让你大开眼界!


    希望通过这篇文章,大家不仅学到了知识,还能会心一笑。AI的世界其实并不枯燥,关键是要找到对的方式去探索。下次我们再来聊聊其他有趣的话题吧!

  • Transformer升级之路:逆用Leaky ReRoPE解决推理成本问题

    在上周的文章《Transformer升级之路:12、无限外推的ReRoPE?》中,我们介绍了ReRoPE和Leaky ReRoPE的创新方法。实验结果表明,它们在几乎不损失训练效果的情况下能够扩展LLM的Context长度,并且实现了“longer context, lower loss”的理想特性。尤其是ReRoPE,似乎表现出了无限的Context处理能力。然而,这些方法也带来了推理阶段的成本增加问题。本文将探讨一种新的解决方案:逆用Leaky ReRoPE。

    回顾RoPE与Leaky ReRoPE

    RoPE与位置编码

    RoPE(Rotary Position Embedding)形式上是一种绝对位置编码,但实际上它实现了相对位置编码。其对应的相对位置矩阵为:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & 3 & \cdots & L-2 & L-1\
    -1 & 0 & 1 & 2 & \cdots & L-3 & L-2\
    -2 & -1 & 0 & 1 & \cdots & L-4 & L-3\
    \vdots & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\
    2-L & 3-L & 4-L & \cdots & -2 & -1 & 0\
    1-L & 2-L & 3-L & \cdots & -3 & -2 & -1\
    \end{array}\right)
    ][/latex]

    Leaky ReRoPE与窗口化处理

    为了在保留局域性的同时避免Long Context导致位置越界问题,Leaky ReRoPE将推理阶段的相对位置矩阵改为:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & \cdots & w-1 & w & \cdots & w+k & \cdots & w+L-1-wk\
    -1 & 0 & 1 & \cdots & w-2 & w-1 & \cdots & w+k-1 & \cdots & w+L-2-wk\
    \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots\
    -w+1 & -w+2 & -w+3 & \cdots & -1 & 0 & \cdots & k-1 & \cdots & L-2-wk\
    \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\
    \end{array}\right)
    ][/latex]

    其中,( w ) 是窗口宽度,( k ) 用来调节可处理的最大长度。

    ReRoPE的无限扩展能力

    ReRoPE直接取了 ( k \to \infty ) 的极限:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & \cdots & w-1 & w & \cdots & w & \cdots & w\
    -1 & 0 & 1 & \cdots & w-2 & w-1 & \cdots & w & \cdots & w\
    \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots\
    -w+1 & -w+2 & -w+3 & \cdots & -1 & 0 & \cdots & w & \cdots & w\
    \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\
    \end{array}\right)
    ][/latex]

    逆用Leaky ReRoPE:让训练阶段变慢,推理阶段变快

    为什么逆用?

    原本的ReRoPE和Leaky ReRoPE在推理阶段增加了计算成本。如果我们反过来在训练阶段使用Leaky ReRoPE,而在推理阶段使用常规的RoPE,能否解决这一问题呢?

    实验与结果

    我们进行了以下实验组合:“GAU + Deep Norm + Tiger + 语言模型”。在训练阶段使用 ( k=1/16, w=128 ) 的Leaky ReRoPE,在推理阶段使用正常的RoPE。测试结果如下:

    测试长度BaselineBaseline-lognNTK-RoPE-fixedNTK-RoPE-logn†-fixedNTK-RoPE-logn-fixedNTK-RoPE-mixedNTK-RoPE-logn†-mixedNTK-RoPE-logn-mixedReRoPE-w256ReRoPE-w256-logn†ReRoPE-w256-lognInvLeaky ReRoPE-w128-lognInvLeaky ReRoPE-w128-b8-lognHFWA512 (训练)
    训练49.41%49.40%49.41%49.41%49.40%49.41%49.41%49.40%49.41%49.41%49.40%49.38%49.62%48.70%
    4096(重复)24.17%24.60%51.86%55.94%62.85%53.09%59.11%68.91%77.90%82.40%85.12%82.25%81.15%80.84%
    4096(不重复)23.16%24.02%39.61%41.11%44.14%40.12%42.38%45.41%48.48%48.85%49.07%48.32%48.85%48.15%

    其中,( b8 ) 是指RoPE的频率底数从10000换成了80000。可以看到,“Leaky ReRoPE → RoPE”的InvLeaky ReRoPE虽然效果上不如“RoPE → ReRoPE/Leaky ReRoPE”,但依然胜过了HFWA,并且由于推理阶段是常规的RoPE,可以套用现成的加速技术,因此依然是有相当竞争力的。

    我们对 [latex]( k, w, b )[/latex] 等参数做了一些简单的调参,发现最优解基本上就是上述两个组合。具体来说:

    调参与训练速度

    • ( k ) 设置为“扩展倍数的2倍的倒数”
    • ( w ) 设置为训练长度的四分之一
    • ( b ) 可选乘以扩展倍数

    在上述实验中,模型参数量为1亿,训练长度为512,每1000步的训练时间从330秒增加到了350秒,增加不到10%。虽然这里有GAU的原因,因为GAU是单头的注意力,本身比多头注意力快。如果是多头注意力或者训练长度更长,增加幅度可能会更大,但估计不会超过50%,依然在可接受范围内。

    小结

    本文提出了Leaky ReRoPE的“逆用”方法,通过在训练阶段使用更大步长的Leaky ReRoPE,使得推理阶段可以退回常规的RoPE,从而保持推理速度不变。实验结果表明,这种方法依然具有相当的竞争力。未来的工作可以进一步优化参数设置,提升模型性能。


    希望这篇文章能够帮助您更好地理解逆用Leaky ReRoPE的方法及其优势。如果有任何疑问或建议,欢迎在评论区留言讨论。

  • 增大Tokenizer词表:LLM续写任务的新挑战与解决方案

    语言模型(LLM)在自然语言处理中的应用越来越广泛,而通过增大Tokenizer的词表来提高压缩率,从而缩短串行长度、降低解码成本,是大家都喜闻乐见的事情。然而,这种方法在带来诸多优点的同时,也可能产生一些问题。本文将探讨增大词表后语言模型在续写任务中遇到的问题,并提出解决方案。

    优劣分析

    优点

    1. 解码速度提升:由于LLM是自回归的,解码过程会随着序列长度的增加变得越来越慢。通过“增大词表 → 提高压缩率 → 缩短串行长度”,可以减少相同文本对应的tokens数量,从而减少解码步数,提升解码速度。
    2. 缓解Exposure Bias:语言模型的训练方式通常是Teacher Forcing,缩短串行长度能够缓解Teacher Forcing带来的Exposure Bias问题,从而可能提升模型效果。

    缺点

    1. 割裂字符联系:增大词表可能会割裂token与token之间在字符层面的联系,影响模型的泛化能力。例如,“太阳能”和“太阳”都是词表中的一个词时,模型可能不知道“太阳能”是由“太阳”和“能”组成,从而难以完成一些子词相关的任务。
    2. 续写问题:增大词表后,常见的命令或短语可能被视为单个token,导致模型在续写时无法正确生成。例如,“import numpy as np”被当作一个token,用户输入“import numpy”时,模型无法续写出“ as np”。

    续写问题

    Armen Aghajanyan分享了一个典型的例子:在训练代码模型时使用超大词表,导致“import numpy as np”变成了一个token。当用户输入“import numpy”时,模型无法续写出“ as np”。这种现象在自然语言模型中也很常见。例如,“太阳能”和“太阳”都是独立的token时,用户输入“太阳”后,模型续写出的内容可能不符合用户的期望。

    参考对策

    虽然Armen Aghajanyan提到的问题确实存在,但笔者认为通过适当的处理,这个问题不仅可以解决,还能转化为增大词表的优点。以下是一个可行的解决方案:

    基于词表的前缀搜索

    假设用户输入了“广州的白云”,Tokenizer将其分为“广州/的/白云”。此时,如果直接将这三个词转换为id输入模型,模型可能无法续写出“广州/的/白云机场”等结果。因此,我们可以进行以下步骤:

    1. 前缀搜索:对“白云”进行词表的前缀搜索,假设搜索结果为“白云”、“白云机场”、“白云山”、“白云路”四个词。
    2. 计算条件概率:用LLM计算以下条件概率:
      [latex][p(\text{白云}|\text{广州, 的})p(\text{白云机场}|\text{广州, 的})p(\text{白云山}|\text{广州, 的})p(\text{白云路}|\text{广州, 的})][/latex]
    3. 归一化与采样:将条件概率归一化后进行采样,决定续写内容。例如,采样结果为“白云机场”,则输出“机场”,并按照“广州/的/白云机场”进行续写。

    这种方法不仅解决了Armen Aghajanyan所提到的问题,还能在词表压缩率高的情况下,一次性生成更多的字。特别地,回退操作只需在采样第一步进行,从第二步开始就不需要回退操作,计算量很少。

    文章小结

    本文介绍了增大词表后LLM在续写任务中可能出现的问题,并分享了参考的解决方案。通过结合基于LLM的续写和基于词表的前缀搜索,可以有效地解决续写问题,并将增大词表的缺点转化为优点。希望这些思路能为语言模型的进一步优化提供参考。

  • Viterbi Sampling算法的改进与完善

    在自然语言处理领域,分词是一个至关重要的步骤。最近,一篇名为《随机分词浅探:从Viterbi Decoding到Viterbi Sampling》的文章中,作者提出了一种名为“Viterbi Sampling”的随机分词算法。本文将详细讨论该算法的改进,并从数学上证明其效果可以与Subword Regularization等价。

    问题分析

    在知乎的评论中,用户 @鹤舞 指出,当前的采样算法可能会在多次二选一的过程中“稀释”了部分方案的出现概率,导致原本分数最高的切分并不是以最高概率出现。

    例如,假设有三种切分方案,每种方案的得分都一样,理应每种方案的出现概率都是1/3。然而,Viterbi Sampling算法将多选一的过程拆分成多步的二选一,从而导致概率分布发生偏移。

    示例分析

    以单词“watching”为例,有三种切分方案:watch ing, wat ching, 和 w atching。按照Viterbi Sampling的操作,先在前两种方案中选择,概率均为1/2;然后再与第三种方案比较,概率依然为1/2。最终,前两种方案的出现概率为1/4,而第三种方案的出现概率变为了1/2。

    解决办法

    为了解决上述问题,可以采用“水塘采样(Reservoir sampling)”的算法。具体来说,每次进行二选一后,同时缓存累积概率,并在后续的二选一过程中使用累积概率进行比较。

    具体实现

    假设前两种切分方案的概率均为1/3,选择其中一种后,总的累积概率为2/3。接下来,新方案被选中的概率为1/3,而不是1/2。这保证了每种方案的出现概率均保持为1/3。

    在实际计算时,为避免指数爆炸问题,可以缓存对数形式的概率,并利用logsumexp函数避免溢出。

    Zlogi = logsumexp(Zlogi-1, αsi)

    相应的实现已经内置在bytepiece>=0.5.0中。

    完美采样的证明

    为了证明改进后的Viterbi Sampling算法是“完美采样”,我们需要回顾Viterbi Decoding的基本原理。Viterbi Decoding通过动态规划找出最优的分词方案,其子串也必须是对应子字节串的最优切分方案。

    数学推导

    通过动态规划,可以计算出每个位置的最优切分方案及其得分。而在Viterbi Sampling中,我们需要对所有切分方案进行采样,其采样概率应与得分成正比。

    Z(c1, c2, ..., cl) = ∑ Z(c1, ..., ck) * e^(α * s(ck+1, ..., cl))

    通过逐步计算累积权重Z,可以实现对所有切分方案的完美采样。

    递归式转换

    在实际计算中,使用对数形式的累积权重Zlog,并通过logsumexp函数进行累积计算。

    Zlog(c1, c2, ..., cl) = logsumexp(Zlog(c1, ..., ck) + α * s(ck+1, ..., cl))

    这样可以避免直接计算指数导致的溢出问题。

    文章小结

    本文通过详细分析和数学推导,完善了之前提出的Viterbi Sampling算法。改进后的算法不仅解决了概率“稀释”问题,而且在效果上与Subword Regularization等价,同时在使用效率上更具优势。

    通过这些改进,Viterbi Sampling算法在实际应用中将具备更高的可靠性和效率,为自然语言处理领域的分词任务提供了更优的解决方案。

  • 探索线性Attention的局限性:从“集中注意力”角度出发

    近年来,Transformer架构在自然语言处理领域取得了显著的成果,而Attention机制则是其核心所在。然而,随着研究的深入,传统的标准Attention机制暴露出了一些计算复杂度和资源需求上的问题,这促使研究者们开始探索更高效的线性Attention。然而,线性Attention在实际效果上却一直不如标准Attention。本文将从“集中注意力”的角度,探讨线性Attention的局限性,并尝试给出一个合理的解释。

    Attention机制的稀疏性

    什么是稀疏性?

    在《从熵不变性看Attention的Scale操作》一文中,我们用信息熵来度量Attention的“集中注意力”程度。熵越低,Attention越有可能集中在某个token上。然而,信息熵只能用于归一化且非负的Attention矩阵,这限制了其适用范围。因此,我们引入了另一种稀疏性度量指标:S(x) = E[|x|] / sqrt(E[x^2])。这个指标与信息熵类似,S(x)越小,表示对应的随机矢量越稀疏,即越有可能“一家独大”。

    标准Attention的稀疏性

    对于标准Attention机制,f = exp,我们可以推导出其稀疏性:

    S(a) = exp(-1/2 * σ^2 * ||q||^2)

    σ||q||趋向无穷大时,S(a)趋向于0,这意味着标准Attention可以任意稀疏地“集中注意力”。

    GAU的稀疏性

    对于Gated Attention Unit (GAU)机制,f = relu2,其稀疏性较为复杂,但通过计算可以发现,只有当偏置项β小于0时,稀疏性才有机会趋于0。这表明,GAU在某些条件下也能实现较高的稀疏性。

    线性Attention的局限性

    极简线性Attention

    对于最简单的线性Attention,即不加任何激活函数f = identical,其稀疏性为:

    S(a) = sqrt(2/π * γ * exp(-β^2/(2γ^2)) + β * erf(β/(2√γ)) / (β^2 + γ^2))

    从图像可以看出,极简线性Attention的稀疏性存在一个较高的下限,这意味着它难以“集中注意力”到关键位置上。

    一般线性Attention

    线性Attention的一般形式为a_j ∝ g(q) ⋅ h(k_j),其稀疏性为:

    S(a) = 1 / sqrt(1 + (σ~ * μ~ * ||q~||_2 / ||q~||_1)^2)

    这表明,要想线性Attention变得稀疏,可以通过降低k~串行的信噪比或增大q的模长。然而,非负型线性Attention通常只能表示绝对位置的重要性,难以表达相对位置的重要性。

    线性衰减Attention

    对于带有显式递归的线性RNN模型,其稀疏性为:

    S(a) = 1 - λ^n / n(1 - λ) * sqrt(1 + λ / (1 + λ^n))

    λ < 1时,随着n趋向无穷大,S(a)趋向0。这意味着这种模型可以实现较高的稀疏性,但其注意力仅能表达固定不变的注意力衰减,难以自适应地关注到长距离的上下文。

    结论

    本文通过Attention矩阵的稀疏程度,考察了不同Attention机制的潜力,得出以下结论:

    1. 标准Attention可以实现任意稀疏的注意力矩阵。
    2. 线性Attention难以实现高稀疏性,尤其是在表示相对位置的重要性时。
    3. 带有显式衰减的线性Attention可以实现稀疏性,但其注意力固定,难以自适应。

    这些发现或许能够解释线性Attention在实际效果上略逊一筹的原因。线性Attention在“集中注意力”方面存在固有的局限性,这使得它在处理复杂上下文时表现不如标准Attention。未来的研究或许需要在如何提高线性Attention的稀疏性和灵活性上继续努力,以期实现更高效且性能优越的Transformer模型。

    参考文献

    1. 《Transformer升级之路:3、从Performer到线性Attention》
    2. 《为什么现在的LLM都是Decoder-only的架构?》
    3. 《从熵不变性看Attention的Scale操作》
    4. 《FLASH:可能是近来最有意思的高效Transformer设计》
    5. 《相对位置编码Transformer的一个理论缺陷与对策》
    6. 《如何度量数据的稀疏程度?》
    7. 《线性Attention的探索:Attention必须有个Softmax吗?》
    8. 《Google新作试图“复活”RNN:RNN能否再次辉煌?》

    通过上述分析,我们不仅理解了不同Attention机制的稀疏性差异,还揭示了线性Attention在实际应用中的局限性。希望本文的讨论能够为未来的研究提供一些新的思路和方向。

  • 深度学习中的状态空间模型(SSM)初探

    引言

    前几天,笔者看了几篇介绍SSM(State Space Model)的文章,才发现原来自己从未认真了解过SSM,于是打算认真去学习一下SSM的相关内容,顺便开了这个新坑,记录一下学习所得。

    SSM的概念由来已久,但这里我们特指深度学习中的SSM,一般认为其开篇之作是2021年的S4,不算太老,而SSM最新最火的变体大概是去年的Mamba。当然,当我们谈到SSM时,也可能泛指一切线性RNN模型,这样RWKV、RetNet还有此前我们在《Google新作试图“复活”RNN:RNN能否再次辉煌?》介绍过的LRU都可以归入此类。不少SSM变体致力于成为Transformer的竞争者,尽管笔者并不认为有完全替代的可能性,但SSM本身优雅的数学性质也值得学习一番。

    尽管我们说SSM起源于S4,但在S4之前,SSM有一篇非常强大的奠基之作《HiPPO: Recurrent Memory with Optimal Polynomial Projections》(简称HiPPO),所以本文从HiPPO开始说起。

    基本形式

    先插句题外话,上面提到的SSM代表作HiPPO、S4、Mamba的一作都是Albert Gu,他还有很多篇SSM相关的作品,毫不夸张地说,这些工作筑起了SSM大厦的基础。不论SSM前景如何,这种坚持不懈地钻研同一个课题的精神都值得我们由衷地敬佩。

    言归正传。对于事先已经对SSM有所了解的读者,想必知道SSM建模所用的是线性ODE系统:

    [latex][ x′(t) = Ax(t) + Bu(t) ][/latex]
    [latex][ y(t) = Cx(t) + Du(t) ][/latex]

    其中 [latex]( u(t) \in \mathbb{R}^{d_i}, x(t) \in \mathbb{R}^d, y(t) \in \mathbb{R}^{d_o}, A \in \mathbb{R}^{d \times d}, B \in \mathbb{R}^{d \times d_i}, C \in \mathbb{R}^{d_o \times d}, D \in \mathbb{R}^{d_o \times d_i} )[/latex]。当然我们也可以将它离散化,那么就变成一个线性RNN模型,这部分我们在后面的文章再展开。不管离散化与否,其关键词都是“线性”,那么马上就有一个很自然的问题:为什么是线性系统?线性系统够了吗?

    我们可以从两个角度回答这个问题:线性系统既足够简单,也足够复杂。简单是指从理论上来说,线性化往往是复杂系统的一个最基本近似,所以线性系统通常都是无法绕开的一个基本点;复杂是指即便如此简单的系统,也可以拟合异常复杂的函数,为了理解这一点,我们只需要考虑一个 [latex]( \mathbb{R}^4 )[/latex] 的简单例子:

    [latex][ x′(t) = \begin{pmatrix} 1 & 0 & 0 & 0 \ 0 & -1 & 0 & 0 \ 0 & 0 & 0 & 1 \ 0 & 0 & -1 & 0 \end{pmatrix} x(t) ][/latex]

    这个例子的基本解是 [latex]( x(t) = (e^t, e^{-t}, \sin t, \cos t) )[/latex]。这意味着只要 [latex]( d )[/latex] 足够大,该线性系统就可以通过指数函数和三角函数的组合来拟合足够复杂的函数,而我们知道拟合能力很强的傅里叶级数也只不过是三角函数的组合,如果再加上指数函数显然就更强了,因此可以想象线性系统也有足够复杂的拟合能力。

    当然,这些解释某种意义上都是“马后炮”。HiPPO给出的结果更加本质:当我们试图用正交基去逼近一个动态更新的函数时,其结果就是如上的线性系统。这意味着,HiPPO不仅告诉我们线性系统可以逼近足够复杂的函数,还告诉我们怎么去逼近,甚至近似程度如何。

    有限压缩

    接下来,我们只考虑 [latex]( d_i = 1 )[/latex] 的特殊情形,[latex]( d_i > 1 )[/latex] 只不过是 [latex]( d_i = 1 )[/latex] 时的并行推广。此时,[latex]( u(t) )[/latex] 的输出是一个标量,进一步地,作为开头我们先假设 [latex]( t \in [0, 1] )[/latex],HiPPO的目标是:用一个有限维的矢量来储存这一段 [latex]( u(t) )[/latex] 的信息。

    看上去这是一个不大可能的需求,因为 [latex]( t \in [0, 1] )[/latex] 意味着 [latex]( u(t) )[/latex] 可能相当于无限个点组成的矢量,压缩到一个有限维的矢量可能严重失真。不过,如果我们对 [latex]( u(t) )[/latex] 做一些假设,并且允许一些损失,那么这个压缩是有可能做到的,并且大多数读者都已经尝试过。比如,当 [latex]( u(t) )[/latex] 在某点 ( n+1 ) 阶可导的,它对应的 ( n ) 阶泰勒展开式往往是 [latex]( u(t) )[/latex] 的良好近似,于是我们可以只储存展开式的 ( n+1 ) 个系数来作为 [latex]( u(t) )[/latex] 的近似表征,这就成功将 [latex]( u(t) )[/latex] 压缩为一个 ( n+1 ) 维矢量。

    当然,对于实际遇到的数据来说,“( n+1 ) 阶可导”这种条件可谓极其苛刻,我们通常更愿意使用在平方可积条件下的正交函数基展开,比如傅里叶(Fourier)级数,它的系数计算公式为:

    [latex][ c_n = \int_0^1 u(t) e^{-2i\pi nt} dt ][/latex]

    这时候取一个足够大的整数 [latex]( N )[/latex],只保留 [latex]( |n| \leq N )[/latex] 的系数,那么就将 [latex]( u(t) )[/latex] 压缩为一个 ( 2N+1 ) 维的矢量了。

    接下来,问题难度就要升级了。刚才我们说 [latex]( t \in [0, 1] )[/latex],这是一个静态的区间,而实际中 [latex]( u(t) )[/latex] 代表的是持续采集的信号,所以它是不断有新数据进入的,比如现在我们近似了 [latex]( [0, 1] )[/latex] 区间的数据,马上就有 [latex]( [1, 2] )[/latex] 的数据进来,你需要更新逼近结果来试图记忆整个 ( [0, 2] ) 区间,接下来是 ( [0, 3] )、( [0, 4] ) 等等,这我们称为“在线函数逼近”。而上面的傅里叶系数公式只适用于区间 ( [0, 1] ),因此需要将它进行推广。

    为此,我们设 [latex]( t \in [0, T] ),( s \mapsto t \leq T(s) )[/latex] 是 ( [0, 1] ) 到 ( [0, T] ) 的一个映射,那么 [latex]( u(t \leq T(s)) )[/latex] 作为 ( s ) 的函数时,它的定义区间就是 [latex]( [0, 1] )[/latex],于是就可以复用傅里叶系数公式:

    [latex][ c_n(T) = \int_0^1 u(t \leq T(s)) e^{-2i\pi ns} ds ][/latex]

    这里我们已经给系数加了标记 [latex]( (T) )[/latex],以表明此时的系数会随着 [latex]( T )[/latex] 的变化而变化。

    线性初现

    能将 [latex]( [0, 1] )[/latex] 映射到 [latex]( [0, T] )[/latex] 的函数有无穷多,而最终结果也因 [latex]( t \leq T(s) )[/latex] 而异,一些比较直观且相对简单的选择如下:

    1. [latex]( t \leq T(s) = sT )[/latex],即将 ( [0, 1] ) 均匀地映射到 ( [0, T] );
    2. 注意 [latex]( t \leq T(s) )[/latex] 并不必须是满射,所以像 [latex]( t \leq T(s) = s + T – 1 )[/latex] 也是允许的,这意味着只保留了最邻近窗口 ( [T – 1, T] ) 的信息,丢掉了更早的部分,更一般地有 [latex]( t \leq T(s) = sw + T – w )[/latex],其中 ( w ) 是一个常数,这意味着 ( T – w ) 前的信息被丢掉了;
    3. 也可以选择非均匀映射,比如 [latex]( t \leq T(s) = T\sqrt{s} )[/latex],它同样是 ( [0, 1] ) 到 ( [0, T] ) 的满射,但 ( s = 1/4 ) 时就映射到 ( T/2 ) 了,这意味着我们虽然关注全局的历史,但同时更侧重于 ( T ) 时刻附近的信息。

    现在我们以 [latex]( t \leq T(s) = (s + 1)w/2 + T – w )[/latex] 为例,代入傅里叶系数公式得到:

    [latex][ c_n(T) = \int_0^1 u(sw + T – w) e^{-2i\pi ns} ds ][/latex]

    现在我们两边求关于 ( T ) 的导数:

    [latex][ \frac{d}{dT} c_n(T) = \frac{1}{w} \left[ u(T) – u(T – w) \right] + \frac{2i\pi n}{w} c_n(T) ][/latex]

    其中我们用了分部积分公式。由于我们只保留了 [latex]( |n| \leq N )[/latex] 的系数,所以根据傅里叶级数的公式,可以认为如下是 [latex]( u(sw + T – w) )[/latex] 的一个良好近似:

    [latex][ u(sw + T – w) \approx \sum_{k=-N}^N c_k(T) e^{2i\pi ks} ][/latex]

    那么 [latex]( u(T – w) = u(sw + T – w) \big|{s=0} \approx \sum{k=-N}^N c_k(T) )[/latex],代入上式得:

    [latex][ \frac{d}{dT} c_n(T) \approx \frac{1}{w} \left[ u(T) – \sum_{k=-N}^N c_k(T) \right] + \frac{2i\pi n}{w} c_n(T) ][/latex]

    将 ( T ) 换成 ( t ),然后所有的 [latex]( c_n(t) )[/latex] 堆在一起记为 [latex]( x(t) = (c_{-N}, c_{-(N-1)}, \ldots, c_0, \ldots, c_{N-1}, c_N) )[/latex],并且不区分 [latex]( \approx )[/latex] 和 [latex]( = )[/latex],那么就可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} \frac{2i\pi n – 1}{w}, & k = n \ -\frac{1}{w}, & k \ne n \end{cases}, \quad B_n = \frac{1}{w} ][/latex]

    这就出现了如上所示的线性ODE系统。即当我们试图用傅里叶级数去记忆一个实时函数的最邻近窗口内的状态时,结果自然而然地导致了一个线性ODE系统。

    一般框架

    当然,目前只是选择了一个特殊的 [latex]( t \leq T(s) )[/latex],换一个 [latex]( t \leq T(s) )[/latex] 就不一定有这么简单的结果了。此外,傅里叶级数的结论是在复数范围内的,进一步实数化也可以,但形式会变得复杂起来。所以,我们要将这一过程推广成一个一般化的框架,从而得到更一般、更简单的纯实数结论。

    设 [latex]( t \in [a, b] )[/latex],并且有目标函数 [latex]( u(t) )[/latex] 和函数基 [latex]( { g_n(t) }_{n=0}^N )[/latex],我们希望有后者的线性组合来逼近前者,目标是最小化 [latex]( L^2 )[/latex] 距离:

    [latex][ \arg\min_{c_1, \ldots, c_N} \int_a^b \left[ u(t) – \sum_{n=0}^N c_n g_n(t) \right]^2 dt ][/latex]

    这里我们主要在实数范围内考虑,所以方括号直接平方就行,不用取模。更一般化的目标函数还可以再加个权重函数 [latex]( \rho(t) )[/latex],但我们这里就不考虑了,毕竟HiPPO的主要结论其实也没考虑这个权重函数。

    对目标函数展开,得到:

    [latex][ \int_a^b u^2(t) dt – 2 \sum_{n=0}^N c_n \int_a^b u(t) g_n(t) dt + \sum_{m=0}^N \sum_{n=0}^N c_m c_n \int_a^b g_m(t) g_n(t) dt ][/latex]

    这里我们只考虑标准正交函数基,其定义为 [latex]( \int_a^b g_m(t) g_n(t) dt = \delta_{m,n} ),( \delta_{m,n} )[/latex] 是克罗内克δ函数,此时上式可以简化成:

    [latex][ \int_a^b u^2(t) dt – 2 \sum_{n=0}^N c_n \int_a^b u(t) g_n(t) dt + \sum_{n=0}^N c_n^2 ][/latex]

    这只是一个关于 [latex]( c_n )[/latex] 的二次函数,它的最小值是有解析解的:

    [latex][ c^*_n = \int_a^b u(t) g_n(t) dt ][/latex]

    这也被称为 [latex]( u(t) )[/latex] 与 [latex]( g_n(t) )[/latex] 的内积,它是有限维矢量空间的内积到函数空间的并行推广。简单起见,在不至于混淆的情况下,我们默认 [latex]( c_n )[/latex] 就是 [latex]( c^*_n )[/latex]。

    接下来的处理跟上一节是一样的,我们要对一般的 [latex]( t \in [0, T] )[/latex] 考虑 [latex]( u(t) )[/latex] 的近似,那么找一个 [latex]( [a, b] )[/latex] 到 [latex]( [0, T] )[/latex] 的映射 [latex]( s \mapsto t \leq T(s) )[/latex],然后计算系数:

    [latex][ c_n(T) = \int_a^b u(t \leq T(s)) g_n(s) ds ][/latex]

    同样是两边求 [latex]( T )[/latex] 的导数,然后用分部积分法:

    [latex][ \frac{d}{dT} c_n(T) = \int_a^b u'(t \leq T(s)) \frac{\partial t \leq T(s)}{\partial T} g_n(s) ds ][/latex]

    [latex][ = \int_a^b \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) du(t \leq T(s)) ][/latex]

    [latex][ = \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) \bigg|_{s=b}^{s=a} – \int_a^b u(t \leq T(s)) d \left[ \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) \right] ][/latex]

    请勒让德

    接下来的计算,就依赖于 [latex]( g_n(t) )[/latex] 和 [latex]( t \leq T(s) )[/latex] 的具体形式了。HiPPO的全称是High-order Polynomial Projection Operators,第一个P正是多项式(Polynomial)的首字母,所以HiPPO的关键是选取多项式为基。现在我们请出继傅里叶之后又一位大牛——勒让德(Legendre),接下来我们要选取的函数基正是以他命名的“勒让德多项式”。

    勒让德多项式 [latex]( p_n(t) )[/latex] 是关于 [latex]( t )[/latex] 的 [latex]( n )[/latex] 次函数,定义域为 [latex]( [-1, 1] )[/latex],满足:

    [latex][ \int_{-1}^1 p_m(t) p_n(t) dt = \frac{2}{2n+1} \delta_{m,n} ][/latex]

    所以 [latex]( p_n(t) )[/latex] 之间只是正交,还不是标准(平分积分为1),[latex]( g_n(t) = \sqrt{\frac{2n+1}{2}} p_n(t) )[/latex] 才是标准正交基。

    当我们对函数基 [latex]( {1, t, t^2, \ldots, t^n} )[/latex] 执行施密特正交化时,其结果正是勒让德多项式。相比傅里叶基,勒让德多项式的好处是它是纯粹定义在实数空间中的,并且多项式的形式能够有助于简化部分 [latex]( t \leq T(s) )[/latex] 的推导过程,这一点我们后面就可以看到。勒让德多项式有很多不同的定义和性质,这里我们不一一展开,有兴趣的读者自行看维基百科介绍即可。

    接下来我们用到两个递归公式来推导一个恒等公式,这两个递归公式是:

    [latex][ p′_{n+1}(t) – p′_{n-1}(t) = (2n+1) p_n(t) ][/latex]
    [latex][ p′_{n+1}(t) = (n+1) p_n(t) + t p′_n(t) ][/latex]

    由第一个公式迭代得到:

    [latex][ p′_{n+1}(t) = (2n+1) p_n(t) + (2n−3) p_{n−2}(t) + (2n-7) p_{n-4}(t) + ⋯ = \sum_{k=0}^n (2k+1) χ_{n−k} p_k(t) ][/latex]

    其中当 [latex]( k )[/latex] 是偶数时 [latex]( χ_k = 1 )[/latex] 否则 [latex]( χ_k = 0 )[/latex] 。代入第二个公式得到:

    [latex][ t p′_n(t) = n p_n(t) + (2n−3) p{n-2}(t) + (2n-7) p_{n-4}(t) + ⋯ ][/latex]

    继而有:

    [latex][ (t+1) p′_n(t) = n p_n(t) + (2n-1) p_{n−1}(t) + (2n-3) p_{n-2}(t) + ⋯ = – (n+1) p_n(t) + \sum_{k=0}^n (2k+1) p_k(t) ][/latex]

    这些就是等会要用到的恒等式。此外,勒让德多项式满足 ( p_n(1) = 1, p_n(-1) = (-1)^n ),这个边界值后面也会用到。

    正如 ( n ) 维空间中不止有一组正交基也一样,正交多项式也不止有勒让德多项式一种,比如还有切比雪夫(Chebyshev)多项式,如果算上加权的目标函数(即 [latex]( ρ(t) ≢ 1 )[/latex] ),还有拉盖尔多项式等,这些在原论文中都有提及,但HiPPO的主要结论还是基于勒让德多项式展开的,所以剩余部分这里也不展开讨论了。

    邻近窗口

    完成准备工作后,我们就可以代入具体的 [latex]( t ≤ T(s) )[/latex] 进行计算了,计算过程跟傅里叶级数的例子大同小异,只不过基函数换成了勒让德多项式构造的标准正交基 [latex]( g_n(t) = \sqrt{\frac{2n+1}{2}} p_n(t) )[/latex]。作为第一个例子,我们同样先考虑只保留最邻近窗口的信息,此时 [latex]( t ≤ T(s) = \frac{(s+1)w}{2} + T – w )[/latex] 将 [latex]( [−1, 1] )[/latex] 映射到 [latex]( [T−w, T] )[/latex],原论文将这种情形称为“LegT(Translated Legendre)”。

    直接代入之前得到的公式,马上得到:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{w}} [u(T) – (−1)^n u(T−w)] – \frac{2}{w} \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) g′_n(s) ds ][/latex]

    我们首先处理 [latex]( u(T−w) )[/latex] 项,跟傅里叶级数那里同样的思路,我们截断 ( n ≤ N ) 作为 [latex]( u\left(\frac{(s+1)w}{2} + T – w\right) )[/latex] 的一个近似:

    [latex][ u\left(\frac{(s+1)w}{2} + T – w\right) ≈ \sum_{k=0}^N c_k(T) g_k(s) ][/latex]

    从而有 [latex]( u(T−w) ≈ \sum_{k=0}^N c_k(T) g_k(−1) = \sum_{k=0}^N (−1)^k c_k(T) \sqrt{\frac{2k+1}{2}} )[/latex] 。接着,利用之前的递归公式得到:

    [latex][ \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) g′n(s) ds = \int{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} p′_n(s) ds ][/latex]

    [latex][ = \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} \left[\sum_{k=0}^{n-1} (2k+1) \chi_{n-1-k} p_k(s) \right] ds ][/latex]

    [latex][ = \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} \left[\sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} g_k(s) \right] ds ][/latex]

    [latex][ = \sqrt{\frac{2n+1}{2}} \sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} c_k(T) ][/latex]

    将这些结果集成起来,就有:

    [latex][ \frac{d}{dT} c_n(T) ≈ \sqrt{\frac{2(2n+1)}{w}} u(T) – \sqrt{\frac{2(2n+1)}{w}} (−1)^n \sum_{k=0}^N (−1)^k c_k(T) \sqrt{\frac{2k+1}{2}} – \frac{2}{w} \sqrt{\frac{2n+1}{2}} \sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} c_k(T) ][/latex]

    再次地,将 [latex]( T )[/latex] 换回 [latex]( t )[/latex],并将所有的 [latex]( c_n(t) )[/latex] 堆在一起记为 [latex]( x(t) = (c_0, c_1, ⋯, c_N) )[/latex],那么根据上式可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} -\frac{2}{w} \sqrt{\frac{(2n+1)(2k+1)}{2}}, & k < n \ -\frac{2}{w} \sqrt{\frac{(2n+1)(2k+1)}{2}} (−1)^{n−k}, & k ≥ n \end{cases}, \quad B_n = \sqrt{\frac{2(2n+1)}{w}} ][/latex]

    我们还可以给每个 [latex]( c_n(T) )[/latex] 都引入一个缩放因子,来使得上述结果更一般化。比如我们设 [latex]( c_n(T) = λ_n \tilde{c}_n(T) )[/latex],代入上式整理得:

    [latex][ \frac{d}{dT} \tilde{c}n(T) ≈ \sqrt{\frac{2(2n+1)}{w}} \frac{u(T)}{λ_n} – \sqrt{\frac{2(2n+1)}{w}} \frac{(−1)^n}{λ_n} \sum{k=0}^N \frac{(−1)^k c_k(T)}{λk} \sqrt{\frac{2k+1}{2}} – \frac{2}{w} \sqrt{\frac{2n+1}{2}} \sum{k=0}^{n-1} \frac{λk}{λ_n} \sqrt{2(2k+1)} \chi{n-1-k} \tilde{c}_k(T) ][/latex]

    如果取 [latex]( λ_n = \sqrt{2} )[/latex],那么 ( A ) 不变,[latex]( B_n = \sqrt{2(2n+1)} )[/latex],这就对齐了原论文的结果。如果取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],那么就得到了Legendre Memory Units中的结果:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} 2n+1, & k < n \ (−1)^{n−k} (2n+1), & k ≥ n \end{cases}, \quad B_n = 2n+1 ][/latex]

    这些形式在理论上都是等价的,但可能存在不同的数值稳定性。比如一般来说当 [latex]( u(t) )[/latex] 的性态不是特别糟糕时,我们可以预期 [latex]( n )[/latex] 越大,[latex]( |c_n| )[/latex] 的值就相对越小,这样直接用 [latex]( c_n )[/latex] 的话 [latex]( x(t) )[/latex] 矢量的每个分量的尺度就不大对等,这样的系统在实际计算时容易出现数值稳定问题,而取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex] 改用 [latex]( \tilde{c}_n )[/latex] 的话意味着数值小的分量会被适当放大,可能有助于缓解多尺度问题从而使得数值计算更稳定。

    整个区间

    现在我们继续计算另一个例子:[latex]( t ≤ T(s) = \frac{(s+1)T}{2} )[/latex],它将 [latex]( [−1, 1] )[/latex] 均匀映射到 [latex]( [0, T] )[/latex],这意味着我们没有舍弃任何历史信息,并且平等地对待所有历史,原论文将这种情形称为“LegS(Scaled Legendre)”。

    同样地,通过代入之前得到的公式:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{T}} u(T) – \frac{1}{T} \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) (s+1) g′_n(s) ds ][/latex]

    利用之前的递归公式得到:

    [latex][ \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) (s+1) g′n(s) ds = \int{-1}^1 u\left(\frac{(s+1)T}{2}\right) \left[g_n(s) + (s+1) g′_n(s)\right] ds ][/latex]

    [latex][ = c_n(T) + \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) \sqrt{\frac{2n+1}{2}} p′_n(s) ds ][/latex]

    [latex][ = c_n(T) + \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) \left[-(n+1) g_n(s) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} g_k(s)\right] ds ][/latex]

    [latex][ = c_n(T) – n c_n(T) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} c_k(T) ][/latex]

    于是有:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{T}} u(T) – \frac{1}{T} \left(-n c_n(T) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} c_k(T)\right) ][/latex]

    将 ( T ) 换回 ( t ),将所有的 ( c_n(t) ) 堆在一起记为 [latex]( x(t) = (c_0, c_1, ⋯, c_N) )[/latex],那么根据上式可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} \sqrt{(2n+1)(2k+1)}, & k < n \ n+1, & k = n \ 0, & k > n \end{cases}, \quad B_n = \sqrt{2(2n+1)} ][/latex]

    引入缩放因子来一般化结果也是可行的:设 [latex]( c_n(T) = λ_n \tilde{c}_n(T) )[/latex],代入上式整理得:

    [latex][ \frac{d}{dT} \tilde{c}n(T) = \sqrt{\frac{2(2n+1)}{T}} \frac{u(T)}{λ_n} – \frac{1}{T} \left(-n \tilde{c}_n(T) + \sum{k=0}^n \sqrt{(2n+1)(2k+1)} \frac{λ_k}{λ_n} \tilde{c}_k(T)\right) ][/latex]

    取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],就可以让 ( A ) 不变,[latex]( B_n = \sqrt{2(2n+1)} )[/latex],就对齐了原论文的结果。如果取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],就可以像上一节LegT的结果一样去掉根号:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} 2(2n+1), & k < n \ n+1, & k = n \ 0, & k > n \end{cases}, \quad B_n = 2(2n+1) ][/latex]

    但原论文没有考虑这种情况,原因不详。

    延伸思考

    回顾Leg-S的整个推导,我们可以发现其中关键一步是将 [latex]( (s+1) g′_n(s) )[/latex] 拆成 [latex]( g_0(s), g_1(s), ⋯, g_n(s) )[/latex] 的线性组合,对于正交多项式来说,[latex]( (s+1) g′_n(s) )[/latex] 是一个 [latex]( n )[/latex] 次多项式,所以这种拆分必然可以精确成立,但如果是傅立叶级数的情况,[latex]( g_n(s) )[/latex] 是指数函数,此时类似的拆分做不到了,至少不能精确地做到,所以可以说选取正交多项式为基的根本目的是简化后面推导。

    特别要指出的是,HiPPO是一个自下而上的框架,它并没有一开始就假设系统必须是线性的,而是从正交基逼近的角度反过来推出其系数的动力学满足一个线性ODE系统,这样一来我们就可以确信,只要认可所做的假设,那么线性ODE系统的能力就是足够的,而不用去担心线性系统的能力限制了你的发挥。

    当然,HiPPO对于每一个解所做的假设及其物理含义也很清晰,所以对于重用了HiPPO矩阵的SSM,它怎么储存历史、能储存多少历史,从背后的HiPPO假设就一清二楚。比如LegT就是只保留 [latex]( w )[/latex] 大小的最邻近窗口信息,如果你用了LegT的HiPPO矩阵,那么就类似于一个Sliding Window Attention;而LegS理论上可以捕捉全部历史,但这有个分辨率问题,因为 [latex]( x(t) )[/latex] 的维度代表了拟合的阶数,它是一个固定值,用同阶的函数基去拟合另一个函数,肯定是区间越小越准确,区间越大误差也越大,这就好比为了一次性看完一幅大图,那么我们必须站得更远,从而看到的细节越少。

    诸如RWKV、LRU等模型,并没有重用HiPPO矩阵,而是改为可训练的矩阵,原则上具有更多的可能性来突破瓶颈,但从前面的分析大致上可以感知到,不同矩阵的线性ODE只是函数基不同,但本质上可能都只是有限阶函数基逼近的系数动力学。既然如此,分辨率与记忆长度就依然不可兼得,想要记忆更长的输入并且保持效果不变,那就只能增加整个模型的体量(即相当于增加hidden_size),这大概是所有线性系统的特性。

    文章小结

    本文以尽可能简单的方式重复了《HiPPO: Recurrent Memory with Optimal Polynomial Projections》(简称HiPPO)的主要推导。HiPPO通过适当的记忆假设,自下而上地导出了线性ODE系统,并且针对勒让德多项式的情形求出了相应的解析解(HiPPO矩阵),其结果被后来诸多SSM(State Space Model)使用,可谓是SSM的重要奠基之作。

    HiPPO框架展现了优雅的数学结构和强大的应用潜力,在处理时间序列数据时提供了一种高效的记忆机制。未来的研究可以进一步探索其在不同领域中的应用和改进。

    参考文献: https://spaces.ac.cn/archives/10114

  • 何加盐深度揭秘:我是怎么找资料的?

    在信息爆炸的时代,获取和整理信息的能力变得尤为重要。何加盐在其博客文章《何加盐深度揭秘:我是怎么找资料的?》中,详细介绍了他搜集资料的技巧和方法。以下是文章中的一些关键内容和技巧总结:

    一、用好搜索引擎

    1. 善于选择时间段

    通过设置搜索时间段,可以过滤掉大量无关信息。例如,想要了解百度创始人李彦宏的早期历程,可以将搜索时间设置在2000-2004年,这样可以找到更多关于他创业初期的报道。

    2. 善用关键词的组合

    关键词组合能让搜索结果更加精准。例如,搜索“程维 滴滴”可能会得到大量杂乱的信息,但如果组合搜索“程维 王刚”,就能找到更多关于滴滴和投资人的相关资料。

    3. 善用一些搜索命令

    • filetype:如“阿里巴巴组织结构 filetype:pdf”,能搜索到特定类型的文件。
    • 减号:如“张一鸣 -演员”,能过滤掉不相关的搜索结果。
    • site:如“马化腾 site:qq.com”,可以只搜索某个特定网站的信息。

    二、用好社交网站

    社交平台如微博、微信、知乎和脉脉等是搜集资料的重要渠道。通过浏览目标人物的社交账号,可以获取大量一手信息。例如,何加盐在写程维时,浏览了程维的所有微博;在写王兴时,浏览了王兴的饭否账号。

    三、用好视频网站

    视频网站是一个信息宝库,特别是知名人物的演讲、采访视频能提供大量鲜活的细节。例如,写程维时,何加盐参考了吴晓波的《二十年二十人》对程维的采访视频。

    四、用好名人演讲

    名人在各种场合的演讲活动通常会透露很多重要信息。马云在“18罗汉大会”上的演讲是了解他创业史的重要资料。

    五、用好传记作品

    传记是了解人物和企业最全面的方式。例如,《腾讯传》是了解腾讯发展历程的必读书目;《这世界既残酷,也温柔》是了解孙宇晨的主要资料来源之一。

    六、用好杂志

    专业杂志如《财经杂志》、《中国企业家》、《南方人物周刊》等,对人物和企业的报道非常深入。例如,何加盐写TMD三部曲时,引用了不少《财经杂志》的内容。

    总结

    何加盐分享的这些方法,旨在帮助大家更高效地搜集和整理信息。在此过程中,要注意两点:一是信息的真伪,需要多方交叉验证;二是使用好的工具,付费版通常能提供更高效的服务。

    希望这些技巧对你有所帮助!


    Learn more:

    1. 何加盐深度揭秘:我是怎么找资料的?-CSDN博客
  • DeepSeek-V2 大模型

    DeepSeek-V2 是一个强大、经济高效的混合专家语言模型。它具有2360亿个总参数,每个标记激活的参数为210亿。相比于DeepSeek 670亿,DeepSeek-V2 在性能上更强大,同时节省了42.5%的训练成本,将KV缓存减少了93.3%,并将最大生成吞吐量提升了5.76倍[1]

    DeepSeek-V2的配置方法如下:

    1. 下载模型:DeepSeek-V2 可以从 HuggingFace 的官方网站下载[1]
    2. 安装依赖:在配置 DeepSeek-V2 之前,确保已经安装了以下依赖项:
    • Python 3.6 或更高版本
    • PyTorch 1.7.0 或更高版本
    • Transformers 4.0.0 或更高版本
    1. 导入模型:在 Python 代码中导入 DeepSeek-V2 模型,可以使用以下代码:
       from transformers import GPT2LMHeadModel, GPT2Tokenizer
    
       model_name = "deepseek-ai/DeepSeek-V2"
       tokenizer = GPT2Tokenizer.from_pretrained(model_name)
       model = GPT2LMHeadModel.from_pretrained(model_name)
    1. 使用模型:使用导入的模型进行文本生成或其他自然语言处理任务。以下是一个简单的示例:
       input_text = "你好,DeepSeek-V2!"
       input_ids = tokenizer.encode(input_text, return_tensors="pt")
       output = model.generate(input_ids, max_length=50)
       generated_text = tokenizer.decode(output, skip_special_tokens=True)
       print(generated_text)

    这些是配置 DeepSeek-V2 的基本步骤。根据具体的应用场景和需求,你可能需要进一步调整模型的参数和设置。


    Learn more:

    1. GitHub – deepseek-ai/DeepSeek-V2: DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model
    2. README.md · deepseek-ai/DeepSeek-V2 at main
    3. DeepSeek-V2/README.md at main · deepseek-ai/DeepSeek-V2 · GitHub

    配置和使用 DeepSeek-V2:强大、经济高效的混合专家语言模型

    DeepSeek-V2 是一款强大且经济高效的混合专家(Mixture-of-Experts, MoE)语言模型。相比于之前的 DeepSeek 67B,DeepSeek-V2 不仅性能更强,还显著降低了训练成本和资源消耗。本文将介绍如何配置和使用 DeepSeek-V2 模型。

    模型简介

    DeepSeek-V2 拥有 2360 亿个总参数,其中每个标记激活 210 亿个参数。与 DeepSeek 67B 相比,DeepSeek-V2 在多个方面表现出色:

    • 性能提升:模型性能显著提升。
    • 成本节约:节省了 42.5% 的训练成本。
    • 资源优化:KV 缓存减少了 93.3%。
    • 吞吐量提升:最大生成吞吐量提升了 5.76 倍。

    详细信息可以参考 DeepSeek-V2 的 GitHub 页面

    模型下载

    DeepSeek-V2 可以从 HuggingFace 的官方网站下载。以下是下载链接:

    环境依赖

    在配置 DeepSeek-V2 之前,确保你的环境中已经安装了以下依赖项:

    • Python 3.6 或更高版本
    • PyTorch 1.7.0 或更高版本
    • Transformers 4.0.0 或更高版本

    导入和使用模型

    导入模型

    在 Python 代码中导入 DeepSeek-V2 模型,可以使用以下代码:

    from transformers import GPT2LMHeadModel, GPT2Tokenizer
    
    model_name = "deepseek-ai/DeepSeek-V2"
    tokenizer = GPT2Tokenizer.from_pretrained(model_name)
    model = GPT2LMHeadModel.from_pretrained(model_name)

    使用模型进行文本生成

    使用导入的模型进行文本生成或其他自然语言处理任务。以下是一个简单的示例:

    input_text = "你好,DeepSeek-V2!"
    input_ids = tokenizer.encode(input_text, return_tensors="pt")
    output = model.generate(input_ids, max_length=50)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(generated_text)

    详细配置和优化

    使用 Huggingface 的 Transformers 进行推理

    你可以直接使用 Huggingface 的 Transformers 库来进行模型推理。以下是一个示例代码:

    import torch
    from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
    
    model_name = "deepseek-ai/DeepSeek-V2"
    tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
    max_memory = {i: "75GB" for i in range(8)}
    model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, device_map="sequential", torch_dtype=torch.bfloat16, max_memory=max_memory, attn_implementation="eager")
    model.generation_config = GenerationConfig.from_pretrained(model_name)
    model.generation_config.pad_token_id = model.generation_config.eos_token_id
    
    text = "An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors. The output is"
    inputs = tokenizer(text, return_tensors="pt")
    outputs = model.generate(**inputs.to(model.device), max_new_tokens=100)
    
    result = tokenizer.decode(outputs[0], skip_special_tokens=True)
    print(result)

    使用 vLLM 进行推理(推荐)

    为了更高效地执行模型推理,可以使用 vLLM 解决方案。以下是示例代码:

    from transformers import AutoTokenizer
    from vllm import LLM, SamplingParams
    
    max_model_len, tp_size = 8192, 8
    model_name = "deepseek-ai/DeepSeek-V2-Chat"
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    llm = LLM(model=model_name, tensor_parallel_size=tp_size, max_model_len=max_model_len, trust_remote_code=True, enforce_eager=True)
    sampling_params = SamplingParams(temperature=0.3, max_tokens=256, stop_token_ids=[tokenizer.eos_token_id])
    
    messages_list = [
        [{"role": "user", "content": "Who are you?"}],
        [{"role": "user", "content": "Translate the following content into Chinese directly: DeepSeek-V2 adopts innovative architectures to guarantee economical training and efficient inference."}],
        [{"role": "user", "content": "Write a piece of quicksort code in C++."}],
    ]
    
    prompt_token_ids = [tokenizer.apply_chat_template(messages, add_generation_prompt=True) for messages in messages_list]
    
    outputs = llm.generate(prompt_token_ids=prompt_token_ids, sampling_params=sampling_params)
    
    generated_text = [output.outputs[0].text for output in outputs]
    print(generated_text)

    许可证和引用

    许可证

    这个代码库使用 MIT 许可证。DeepSeek-V2 Base/Chat 模型的使用遵循模型许可证。DeepSeek-V2 系列(包括 Base 和 Chat)支持商业用途。

    引用

    如果你在研究中使用了 DeepSeek-V2,请引用以下文献:

    @misc{deepseekv2,
          title={DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model}, 
          author={DeepSeek-AI},
          year={2024},
          eprint={2405.04434},
          archivePrefix={arXiv},
          primaryClass={cs.CL}
    }

    联系方式

    如果你有任何问题,请在 GitHub 提出 issue 或联系 service@deepseek.com。


    更多信息请参考以下链接:

    1. GitHub – deepseek-ai/DeepSeek-V2
    2. README.md · deepseek-ai/DeepSeek-V2 at main
    3. DeepSeek-V2/README.md at main · deepseek-ai/DeepSeek-V2 · GitHub
  • Caddy 2中配置缓存

    在Caddy 2中配置缓存可以使用cache-handler插件。以下是配置Caddy 2缓存的步骤:

    1. 安装cache-handler插件:首先,确保已安装Caddy 2,并且可以使用插件。然后,下载并安装cache-handler插件。可以从GitHub的caddyserver/cache-handler仓库中获取插件的最新版本。
    2. 配置全局缓存选项:在Caddyfile中配置全局缓存选项。这些选项将适用于所有站点。以下是一些常用的全局选项:
    • order cache before rewrite:确保缓存处理在重写之前执行。
    • cache:启用缓存处理。
    • cache.allowed_http_verbs:允许被缓存的HTTP方法,默认为GET和HEAD。
    • cache.api.basepath:缓存管理API的基本路径。
    • cache.badger.path:配置Badger缓存存储的路径。
    • cache.cache_name:覆盖在Cache-Status响应头中使用的缓存名称。
    • cache.default_cache_control:如果上游未设置Cache-Control响应头,则设置默认值。 你可以根据需要配置其他选项。完整的全局选项列表可以在cache-handler插件的文档中找到[1]
    1. 配置站点缓存选项:在Caddyfile中为每个站点配置缓存选项。以下是一个示例配置:
       example.com {
         cache
         reverse_proxy your-app:8080
       }

    在这个示例中,cache指令启用了缓存处理,并将请求代理到your-app:8080

    1. 配置缓存键:你可以使用cache_keys指令为特定的URI配置缓存键生成规则。例如:
       cache_keys {
         .+\.css {
           disable_body
           disable_host
           disable_method
           disable_query
           headers X-Token Authorization
         }
       }

    在这个示例中,所有以.css结尾的URI将使用指定的规则生成缓存键。

    1. 配置CDN管理(可选):如果你使用CDN代理请求,可以配置CDN管理选项。这些选项将与缓存处理一起使用。例如:
       cdn {
         provider fastly
         api_key XXXX
         dynamic
         email darkweak@protonmail.com
         hostname domain.com
         network your_network
         strategy soft
         service_id 123456_id
         zone_id anywhere_zone
       }

    在这个示例中,使用Fastly作为CDN提供商,并配置了相关的API密钥、邮箱、主机名等信息。

    1. 保存并重新加载Caddy配置:完成配置后,保存Caddyfile并重新加载Caddy配置,以使更改生效。

    这些是配置Caddy 2缓存的基本步骤。你可以根据需要调整和扩展这些配置选项。请参考cache-handler插件的文档以获取更多详细信息和选项[1]


    Learn more:

    1. GitHub – caddyserver/cache-handler: Distributed HTTP caching module for Caddy
    2. State of HTTP Caching in Caddy 2 – Help – Caddy Community
    3. 【Caddy2】最新Caddy2配置文件解析 – 詩 – 博客园

    darkweak/souin 是一个HTTP缓存系统,符合RFC标准,并与@tyktechnologies、@traefik、@caddyserver、@go-chi、@bnkamalesh、@beego、@devfeel、@labstack、@gofiber、@go-goyave、@go-kratos、@gin-gonic、@roadrunner-server、@zalando、@zeromicro、@nginx和@apache兼容[1]。它可以作为反向代理缓存系统,可以放置在当前反向代理(如Apache、Nginx)的顶部,也可以作为Træfik、Caddy或Tyk等喜爱的反向代理的插件使用。由于它是用Go语言编写的,可以部署在任何服务器上,并且由于具有Docker集成,可以轻松安装在Swarm或Kubernetes实例上。它支持Vary、请求合并、陈旧的Cache-Control和其他与RFC-7234相关的规范,还支持新编写的RFC(目前处于草案阶段)http-cache-groups和http-invalidation。它还支持ESI标签,感谢go-esi包的支持[1]

    Souin的配置文件存储在/anywhere/configuration.yml中,可以根据需要提供自己的配置文件。配置文件中包含了各种配置选项,如缓存时间、反向代理URL、API配置、缓存键配置等[1]

    Souin还提供了各种插件,如Beego过滤器、Caddy模块、Chi中间件、Dotweb中间件、Echo中间件、Fiber中间件、Gin中间件、Goa中间件、Go-zero中间件、Goyave中间件、Hertz中间件、Kratos过滤器、Roadrunner中间件、Skipper过滤器、Træfik插件、Tyk插件、Webgo中间件、Prestashop插件和Wordpress插件等[1]

    Souin还支持Prometheus API、Souin API和Security API,可以用于监控和管理缓存系统[1]

    总结:darkweak/souin是一个符合RFC标准的HTTP缓存系统,可以作为反向代理缓存系统使用,也可以作为插件嵌入到其他反向代理中。它支持各种配置选项和插件,并提供了API用于监控和管理缓存系统。


    Learn more:

    1. GitHub – darkweak/souin: An HTTP cache system, RFC compliant, compatible with @tyktechnologies, @traefik, @caddyserver, @go-chi, @bnkamalesh, @beego, @devfeel, @labstack, @gofiber, @go-goyave, @go-kratos, @gin-gonic, @roadrunner-server, @zalando, @zeromicro, @nginx and @apache
    2. darkweak · GitHub
    3. Releases · darkweak/souin · GitHub
  • 深入解析 LoRA+:如何通过调整学习率进一步优化LLM

    在当前大规模语言模型(LLM)的参数高效微调方法中,LoRA(Low-Rank Adaptation)无疑是一个重要的手段。此前,我们在《梯度视角下的LoRA:简介、分析、猜测及推广》中曾简单讨论过LoRA。今天,我们来学习LoRA的一个新结论:给LoRA的两个矩阵分配不同的学习率,LoRA的效果还能进一步提升。这一结论出自最近的论文《LoRA+: Efficient Low Rank Adaptation of Large Models》(下称“LoRA+”)。

    为什么调整学习率显得如此重要?

    乍一看,给不同的矩阵分配不同的学习率似乎并没有什么特别之处,因为配置不同的学习率相当于引入了新的超参数,而通常来说,只要引入并精调超参数,模型性能都会有所提升。然而,“LoRA+”的特别之处在于,它从理论角度肯定了这一必要性,并且明确指出最优解必然是右矩阵的学习率大于左矩阵的学习率。

    LoRA基本原理回顾

    假设预训练参数为

    [latex]( W_0 \in \mathbb{R}^{n \times m} )[/latex]

    ,如果使用全量参数微调,那么增量也是一个 ( n \times m ) 矩阵。为了降低参数量,LoRA将更新量约束为低秩矩阵,即设 ( W = W_0 + AB ),其中

    [latex]( A \in \mathbb{R}^{n \times r}, B \in \mathbb{R}^{r \times m}, r \ll \min(n, m) )[/latex]

    。在训练时,只更新 ( A ) 和 ( B )。

    为了便于理解,我们假设层的输入是

    [latex]( X \in \mathbb{R}^{b \times n} )[/latex]

    ,层的运算为

    [latex]( XW = X(W_0 + AB) )[/latex]

    。由于“LoRA+”的结论跟预训练权重无关,不失一般性可以设

    [latex] ( W_0 = 0 )[/latex]

    ,那么层运算简化为

    [latex]( Y = XAB \in \mathbb{R}^{b \times m} )[/latex]

    结论简析

    “LoRA+”的结论是:为了使LoRA的效果尽可能接近最优,权重 ( B ) 的学习率应该要大于权重 ( A ) 的学习率。

    这个结论的核心在于,虽然 ( A ) 和 ( B ) 在表面上是对称的,但实际上它们有着固有的不对称性。即使将 ( A ) 或 ( B ) 全零初始化,结论依然成立。

    数值稳定性与贡献相当假设

    1. 数值稳定性

    数值稳定性意味着 ( X )、 ( XA )、 ( XAB ) 的每个分量都应该是 ( O(1) ) 级别的,而不依赖于网络宽度 ( n, m )。虽然 ( XA ) 是中间变量,但它的数值稳定性对梯度稳定性至关重要。

    为了实现数值稳定性,假设 ( X ) 是 ( O(1) ),那么 ( A ) 和 ( B ) 应该分别用 ( 1/n ) 和 ( 1/r ) 的方差初始化。

    2. 贡献相当

    为了使LoRA最优, ( A ) 和 ( B ) 两个矩阵对效果应该有同等程度的贡献。我们可以通过损失函数 ( L ) 的变化来衡量 ( A ) 和 ( B ) 的贡献:

    [latex][ L(A + \Delta A, B + \Delta B) – L(A, B) \approx \langle \frac{\partial L}{\partial A}, \Delta A \rangle + \langle \frac{\partial L}{\partial B}, \Delta B \rangle ][/latex]

    在Adam优化器中,如果两个参数的学习率之比是 ( \lambda ),那么经过长期训练后,这两个参数的数量级之比也是

    [latex]( \lambda )[/latex]

    。因此,如果 [latex]( \eta_B / \eta_A = O(\sqrt{n}) )[/latex],那么 ( B ) 和 ( A ) 的数量级之比也是 [latex]( O(\sqrt{n}) )[/latex],与我们的期望一致。

    快速推导

    通过矩阵求导,我们可以得到:

    [latex][ \frac{\partial L}{\partial A} = X^\top \frac{\partial L}{\partial Y} B^\top, \quad \frac{\partial L}{\partial B} = A^\top X^\top \frac{\partial L}{\partial Y} ][/latex]

    结合数值稳定性和贡献相当的假设,可以推导出:

    [latex][ \eta_B / \eta_A = O(\sqrt{n}) ][/latex]

    总结

    在这篇文章中,我们介绍并推导了“LoRA+”的结果,它支持LoRA的两个低秩矩阵 ( A ) 和 ( B ) 存在固有的不对称性。不管将哪个矩阵全零初始化,都应该将 ( B ) 的学习率设置得大于 ( A ),以达到更优的效果。这一理论不仅在实践中有效,也为我们提供了一个经典的理论指导训练的范例。