每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/
在过去的几年中,我们见证了开源模型在数量和质量上的惊人增长。
平台如Hugging Face已经使得广泛的模型,包括大型语言模型(LLM)和扩散模型,变得易于获取,赋予了开发者自由和高效创新的能力。开发者享有更大的自主权,他们可以随意微调和组合不同的模型,这促使了像检索增强生成(RAG)这样的创新方法和高级代理的创建。从经济角度看,开源模型提供了可观的成本节约,使得使用较小、专用的模型在预算上比使用通用模型如GPT-4更为经济。
开源模型是一个吸引人的解决方案,但接下来的挑战是什么呢?不像使用像OpenAI这样的模型端点,其中模型是API背后的一个可扩展的黑盒子,部署您自己的开源模型引入了扩展挑战。确保您的模型能够有效地随生产流量扩展,并在流量高峰期间保持流畅的体验至关重要。此外,高效管理成本也很重要,这样您只需为实际使用的资源付费,避免月底时出现经济上的意外。
真正的解决方向:用于GPU的无服务器功能。有趣的是,这听起来像是现代无服务器架构(如AWS Lambda)已经解决的挑战——这种解决方案已经存在了近十年。然而,当涉及到AI模型部署时,情况并非如此。
用于AI部署的无服务器功能的限制是多方面的。
- 没有GPU支持。像AWS Lambda这样的平台不支持GPU。这不仅仅是技术疏忽;它植根于架构和实际考虑。
- GPU不能轻易共享。GPU虽然是高度可并行的设备,但在同时处理多个模型的多个推理任务上不够灵活。
- GPU昂贵。它们适用于模型推理任务,但维护成本高昂,特别是如果不连续使用的话。
接下来,让我们来看看我们的扩展旅程以及我们途中学到的重要教训。
冷启动问题
在我们开始着手扩展之前,我们遇到了臭名昭著的“冷启动”问题。这个问题在三个不同阶段表现出来:
云服务配置:
这一阶段涉及云服务商分配实例并将其整合到我们的集群中所需的时间。这一过程变化很大,快则30秒,慢则几分钟,甚至在某些情况下,特别是对于需求高的实例,如Nvidia A100和H100 GPU,可能需要几个小时。
容器镜像拉取:
与简单的Python工作镜像不同,AI模型服务镜像非常复杂,因为它们需要依赖和自定义库。虽然云服务商提供的网络带宽高达数千兆,但我们的经验常常看到下载速度远低于这一数字,镜像拉取时间约为3分钟。
模型加载
这里所需的时间大多取决于模型的大小,像LLM和扩散模型这样的大型模型因其数十亿参数而需要更长的时间。例如,加载一个5GB的模型,如Stable Diffusion 2,可能需要约1.3分钟,而更大的模型,如Llama 13B和Mixtral 8x7B,则可能需要3.5分钟和12.5分钟。
我们为每个冷启动问题阶段制定了具体策略,以尽量减少延迟。在接下来的部分中,我们将更详细地探讨每一个策略和解决方案。
云服务配置解决
与无服务器CPU的同质环境相比,处理GPU时管理各种计算实例类型至关重要,每种类型都针对特定用例进行了优化。例如,IO密集型的大型语言模型(LLMs)需要高GPU内存带宽和容量,而生成模型则需要更强大的GPU计算能力。
在流量高峰期间确保可用性,通过维护所有GPU实例类型可以导致成本过高。为了避免闲置实例带来的经济压力,我们实施了“待命实例”机制。我们没有为可能的最大负载做准备,而是保持了与增量扩展步骤大小相匹配的待命实例数量。例如,如果我们每次按两个GPU扩展,我们需要准备两个待命实例。这使我们能够在需求激增时迅速增加资源,大大减少等待时间,同时控制成本。
在多租户环境中,多个团队或者在我们的案例中,多个组织共享一个公共资源池,我们可以实现更高的利用率。这种共享环境允许我们平衡不同的资源需求,有助于提高成本效率。然而,管理多租户引入了挑战,比如执行配额和确保网络隔离,这可以增加集群的复杂性。
容器镜像拉取解决
无服务器CPU工作负载通常使用轻量级镜像,如Python slim镜像(约154MB)。与此形成鲜明对比的是,为服务LLM构建的容器镜像可能要大得多(6.7GB);这种大小的大部分来自运行AI模型所需的各种依赖。
尽管云服务商宣传具有高带宽网络,实际情况往往不尽如人意,实际下载速度只是承诺速率的一小部分。实际上,很大一部分文件从未被使用过。一种方法是优化容器镜像本身,但这很快被证明是难以管理的。相反,我们转而专注于按需文件拉取方法。具体来说,我们首先只下载镜像元数据,实际的远程文件稍后根据需要再获取。此外,我们利用集群内的点对点网络大幅提高了拉取效率。
通过这些优化,我们将镜像拉取时间从几分钟减少到了几秒钟。然而,我们都知道这种测量方法是“作弊”,因为实际文件此时还未拉取。真正的文件拉取发生在服务运行时。因此,建立一个服务框架,允许您在不同的生命周期阶段定义行为,如初始化和服务是至关重要的。通过在初始化期间完成所有引导工作,我们可以确保所有文件依赖都已拉取。这样,当服务时间到来时,就不会因文件拉取而造成延迟。
模型加载解决
最初,模型加载的最直接方法是从远程存储库如Hugging Face直接获取。使用内容交付网络(CDNs)、NVMe SSDs和共享内存,我们可以消除一些瓶颈。虽然这种方法有效,但远非最佳。
为了改进这一过程,我们考虑使用区域内网络带宽。我们在分布式文件系统中对模型进行了分块,允许并行下载。这极大地提高了性能,但我们仍然遇到了云提供商的网络带宽瓶颈。
为了应对这一问题,我们进一步优化利用集群内网络带宽通过点对点共享和利用本地缓存。虽然改进显著,但它们增加了过程的复杂性,我们需要从开发者那里抽象出来。
即使采用了上述做法,我们仍然遭受一个序列化瓶颈:需要等待每个步骤完成后才能进行下一个步骤。模型必须完全下载到持久驱动器,然后才能加载到CPU内存中,再转移到GPU。
我们转向使用基于流的方法加载模型权重,利用我们已经建立的分布式文件缓存系统。这个系统允许程序操作,仿佛所有文件逻辑上都在磁盘上可用。实际上,所需数据是按需从远程存储中获取的,因此绕过了磁盘写入。通过使用像Safetensors这样的格式,我们可以通过内存映射(mmap)高效地将模型权重加载到主内存中,然后以流式方式加载到GPU内存中。
此外,我们采用了异步写入磁盘的方法。这样做,我们在本地磁盘上创建了一个更快访问的缓存层。因此,仅有代码更改的新部署可以绕过较慢的远程存储获取阶段,直接从本地缓存读取模型权重。