使用 Apple 的 MLX 框架在本地部署 LLM
2023年12月,Apple发布了新的MLX深度学习框架,这是一个用于在Apple芯片上进行机器学习的阵列框架,由其机器学习研究团队开发。本教程将探讨该框架,并演示如何在MacBookPro(MBP)上本地部署Mistral-7B模型。我们将设置一个本地聊天界面来与已部署的模型进行交互,并根据每秒生成的令牌测试其推理性能。此外,我们将深入研究MLXAPI,以了解用于改变模型行为和影响生成文本的可用杠杆。
和往常一样,相关代码可以在公开的GitHub存储库中找到:。
为什么这很重要?Apple的新机器学习框架MLX具有在Apple芯片上进行机器学习的统一内存架构,与其他深度学习框架相比具有显着优势。与PyTorch和Jax等传统框架不同,这些框架需要在CPU和GPU之间进行成本高昂的数据复制,而MLX将数据维护在共享内存中,两者都可以访问。这种设计消除了数据传输的开销,促进了更快的执行,特别是对于机器学习中常见的大型数据集。对于Apple设备上的复杂ML任务,MLX的共享内存架构可以显著加快速度。此功能使MLX与希望在设备(例如iPhone)上运行模型的开发人员高度相关。
安装步骤初始设置在部署模型之前,需要进行一些设置。首先,必须安装特定的库。在进行安装之前,请记得创建一个虚拟环境:
pipinstallmlx-lm
这个库允许我们在本地部署一个大型语言模型(LLM),并只需五行代码就能运行它:
frommlx_lmimportload,generatemodel,tokenizer=load("mistralai/")prompt="""s[INST]Helloworld![/INST]"""response=generate(model,tokenizer,prompt=prompt)print(response)第一次执行此脚本时,它将下载模型,可能需要一些时间。在后续运行中,模型将从本地缓存加载,大大加快了这个过程。一旦模型被下载,我们就会收到响应:
根据下面的图片,我们深入了解下背后的原理:
一旦调用load()方法,它会检查模型是否在本地机器上可用。如果不存在,该方法会从HuggingFaceModelHub下载模型。加载权重后,它们将被转换为MLX格式。此外,如果在配置中指定,模型将进行量化。
量化和可转换的模型请注意,模型的配置未指定量化,这意味着我们将加载模型的完整权重。但是,可以使用以下命令将模型的原始权重转换为MLX格式()并同时进行量化:
_to_torch_model-q
HuggingFace上还有一个活跃的MLX社区,该社区已经将多个模型转换为MLX格式:
HuggingFaceMLX社区:
加载格式的模型示例:
Mistral指令模型代码的另一个重要功能是提示。大型语言模型(LLM)越来越多地用于聊天机器人应用程序,以实现更自然的对话。与简单地生成连续文本不同,聊天机器人需要理解对话上下文,其中包括“用户”和“助手”等不同角色之间的交流。模型输入由一系列消息组成,而不是单个段落。每个模型通常都有自己的聊天模板,我们可以从他们的模型页面看到Mistral的模型模板是如何显示的:
Mistral的模型聊天模板:
在上面的示例代码中,我们通过将特殊标记插入到字符串中来手动应用此模板。稍后,我们将探索一种更有效的方法来实现这一目标。
聊天机器人界面我们已经下载了Mistral-7B模型的指导版本,我们应该将其用作聊天机器人模型来最大限度地发挥其潜力。幸运的是,这可以通过Streamlit轻松完成,这是一个开源框架,允许我们只需几行代码即可构建聊天机器人界面。
第一步:安装Streamlit:pipinstallstreamlit
我们不会涵盖整个应用程序(完整的代码可以在GitHub上找到),但其中一些值得注意的亮点包括:
第二步:加载模型#缓存模型加载,以避免每次重新加载@_resourcedefload_model():model,tokenizer=load("mistralai/")returnmodel,tokenizermodel,tokenizer=load_model()就像在我们的第一个示例中一样,我们利用mlx_lm库来加载我们的模型。为了防止每次向聊天机器人发送新消息时重新加载模型,我们利用Streamlit的缓存管理,使用_resource修饰符。
第三步:跟踪对话类似于缓存模型,我们还需要跟踪整个对话。聊天机器人使用一种简单的方法记住先前对话的部分:每次接收到新的用户输入时,整个先前的对话以一个长提示的形式发送到模型。为了跟踪对话,我们初始化一个有状态的变量,如下所示:
if'messages'_state:_state['messages']=[]
然后,我们将添加用户和助手的消息,如下所示:
_state['messages'].app({"role":"user","content":prompt})_state['messages'].app({"role":"assistant","content":response})第四步:将对话历史转换为所需的格式Mistral-7B-Instruct模型需要一种非常具体的格式来反映之前的对话。我们可以使用tokenizer的apply_chat_template()方法将对话历史转换为符合此规范的一个长提示:
formatted_conversation=_chat_template(_state['messages'],tokenize=False)
通过运行以下命令来测试,看看它是如何工作的,并确保它正常运行:
fromtransformersimportAutoTokenizertokenizer=_pretrained("mistralai/")chat=[{'role':'user','content':'Hello,howareyou?'},{'role':'assistant','content':'I\\'mgood,?'},{'role':'user','content':'CanyoutellmetheweatherforecastforLondon?'},{'role':'assistant','content':'Sure,theforecastforLondonissunnywithahighof23degrees.'},{'role':'user','content':'Thankyou,that\\'sveryhelpful!'}]print(_chat_template(chat,tokenize=False))我们得到的结果是:
s[INST]Hello,howareyou?[/INST]I'mgood,?/s[INST]CanyoutellmetheweatherforecastforLondon?[/INST]Sure,theforecastforLondonissunnywithahighof23degrees./s[INST]Thankyou,that'sveryhelpful![/INST]
结果显示聊天模板方法正常运作,接下来可以用它来格式化我们的对话历史。
第五步:时间测量我们还将测量接收响应所需的时间,并计算模型每秒生成的令牌数(TPS)。从技术上讲,这个度量并不完全准确,因为它没有考虑模型处理提示所需的时间(随着对话的进行而增加)。然而,从用户体验的角度来看,这种区别通常不太明显。因此,我将在此使用此方法进行测量。
计算令牌数示例:
第六步:测试聊天机器人通过键入以下内容来启动聊天机器人:
启动后将自动在http://localhost:8501/上打开一个浏览器选项卡(如果没有,请在浏览器中键入此地址)。
现在我们可以开始与模型进行交互:
一开始,每秒生成令牌约为15个,后来随着对话时间的延长,它下降到12-13个。这是因为模型需要更多时间来解析整个上一个对话,这在本例中我们测量TPS的方式中有所体现。
内存消耗当然,一个关键问题是这个聊天机器人和本地部署的LLM消耗了多少内存?在MBPM1Max上运行,具有64GB内存的初始脚本使用了14GB内存(通过top-omem查看)。
然而,一旦对话变得更长,内存消耗迅速上升到46GB,并保持在那里。我怀疑这是程序被允许使用的内存的最大值:
探索MLXAPI有时我们希望我们的聊天机器人表现不同,例如,生成更长或更短的答案。在上面的例子中,当我以“你好”开始对话时,响应对我来说太冗长了。请注意,这与设置max_tokens参数是分开的。如果模型以更长的消息响应,并且max_tokens参数设置得很低,例如在50个新令牌的情况下,模型的响应将被截断。
通常,还有其他模型推理参数可用于引导模型的行为,例如重复惩罚或长度惩罚。但是,MLXAPI还不支持这些参数。要了解支持哪些参数,我们可以深入研究MLX代码并检查generate()API:
_argument("--prompt",default=DEFAULT_PROMPT,help="Messagetobeprocessedbythemodel")_argument("--max-tokens","-m",type=int,default=DEFAULT_MAX_TOKENS,help="Maximumnumberoftokenstogenerate",)_argument("--temp",type=float,default=DEFAULT_TEMP,help="Samplingtemperature")_argument("--seed",type=int,default=DEFAULT_SEED,help="PRNGseed")到目前为止,它只支持'max_tokens'、'temp'和'seed'。但是,我预计随着时间的推移,MLX研究团队或社区将添加其他推理参数。
结论我们将功能非常强大的Mistral-7B模型本地部署到具有64GB内存的MacbookPro上。我们还创建了一个聊天机器人界面来与模型进行交互。这仅仅是一个开始,它无疑预示着未来,本地LLM部署将变得更加普遍和重要。
有很多方法可以继续和改进本教程,我将留给读者。一些想法包括:
探索其他LLM和/或使用量化版本
改进了添加文件上传的界面,或用于更改推理参数(例如温度、最大令牌数等)的字段
更密切地测量和监控内存消耗,并测试限制
高级:克隆MLX框架并实现其他推理参数
参考链接:MLX深度学习框架:
项目地址:
Mistral-7B:
HuggingFaceMLX社区:
加载格式的模型示例:
Mistral的模型聊天模板:
计算令牌数示例:
推荐阅读
-
古代劳动人民拿啥来御寒?一身浩然正气还是机体摩擦生热?
我可以非常确切的告诉你,都不是,但这个问题的角度相当刁钻,必须要从老祖宗的衣食住行方方面面进行无微不至的考虑,可谓是能把人的心都操碎了,话不多白扯,咱进入正题。首先要深究的便是不同时代气候温度差异,学者竺可桢先生所著的《中国近五千年来气候变迁的初步研究》一书中,便第一次系统的研究了从BC3000到2...
-
投资界快讯|医疗设备研发制造商“普博科技”获达晨创投数千万元A轮融资
投资界1月13日消息,医疗设备研发制造厂商“普博科技”正式对外宣布,已于近日完成了数千万元A轮融资,由达晨创投领投。据了解,这是达晨创投2018年在医疗健康领域的第一笔投融资事件。普博科技是一家集专业研发、生产、销售医疗设备于一体的医疗设备研发制造厂商,成立于2007年,总部位于深圳,产品主要有自主...
-
电网“黑科技”轻松消除树线矛盾
当我们想到电网,脑海中可能会浮现出一些常见的场景:电线如同蜘蛛网般纵横交错,跨越道路和房屋,将电力输送到每一个角落。但是,你有没有想过,电网也能成为解决城市中树木与电线交叉的矛盾的“黑科技”?是的,你没有听错,让我们一起来探索这个令人惊叹的创新!在现代城市中,随着城市化的加速发展,越来越多的树木被种...
-
杰赛科技副总裁吴阳阳:正常的创业生态应该是金字塔状
说起物联网,可能大家都会想起“极客”、“创客”这些酷炫的词汇,还有智能家居、可穿戴设备这些时髦的产品。但如果小编告诉你,一个有军工背景的上市大企业也在玩物联网,而且一玩就是十几年,你是否会觉得很惊讶呢?2015年10月20日上午,由广东省物联网协会主办的“物联网百强企业行活动”就走访了这家公司——广...