1. Ollama 模型性能对比
为了解决这个问题,查阅了大量 Ollama 资料,基本可以确定以下三点信息:
- Ollama 会自动适配可用英伟达(NVIDIA)显卡。若显卡资源没有被用上,应该是显卡型号不支持导致的。
- Ollama 支持 AMD 显卡的使用。
- 对于 Apple 用户,Ollama 也开始支持 Metal GPUs 方案。
然而,Metal 支持方案实际上指的是使用 M 系列芯片的 Apple 用户,Intel 芯的 Mac 并不支持 Metal GPU 加速。这导致在 Intel Mac 上只能依赖 CPU 进行推理。
当时我陷入自我怀疑,难道是预量化模型的缘故只能适配到 CPU?带着这个疑问下载了一个 Qwen chat 版本进行了同环境的对比验证。结果显示,两者相差约 20 秒,并且两次调用均未使用系统 GPU 资源进行推理。使用一般 chat 版本在仅使用 CPU 算力的情况下比 gguf 版本响应速度稍快,但 69 秒的耗时仍然较慢。
>>> function ollama_transfor_msg totally use 69.74513030052185 seconds
>>> 是的,中医理论可以解释并尝试解决这些症状。
全身乏力和心跳过速可能是由多种原因引起的。在中医看来,这可能与脏腑功能失调、气血不畅、阴阳失衡等因素有关。
例如,心气不足可能导致心跳过速,而脾虚则可能导致全身乏力。另外,如果肝脏的功能不好,也可能导致这种症状。
因此,治疗方案可能会根据你的具体情况进行调整,可能包括中药、针灸、推拿等方法。同时,中医强调调养身体的整体健康,包括饮食习惯、生活方式等方面,也会对改善这些症状有帮助。
>>> function ollama_transfor_msg totally use 90.6007969379425 seconds
>>> 中国传统医学,也就是中医,对于全身乏力和心跳过速等症状有自己的理论解释和治疗方案。
1. 全身乏力:中医认为这是'气虚'或者'阳虚'的表现。气是维持人体生命活动的物质基础,如果气不足,就会出现乏力、疲劳等症状。可能的原因包括饮食不当、劳累过度、久病体弱等。中医会通过调理饮食,增加营养,适当运动,以及服用补气的药物来改善。
2. 心跳过速:中医将其称为'心悸'或'心动过速',可能与心脏气血不足、心阴亏损或者有某些病理因素如痰饮、瘀血等有关。中医治疗会根据具体病因采用益气养阴、化痰活血的方法,有时还会使用中药如炙甘草汤、归脾汤等。
然而,值得注意的是,虽然中医理论能够解释和在一定程度上处理这些症状,但在现代医学中,全身乏力伴随心跳过速也可能是心脏疾病(如心律失常)或其他疾病的症状。如果患者持续出现这些症状,应尽快就医,由专业医生进行诊断和治疗。
2. 基于 transformers 实现
到目前为止能够确定的是:
- Metal 只支持 M 系列芯片与 Intel 无缘。
- 受限于硬件性能,大参数模型无法在短时间内响应。
为了满足以上条件,这里选用 Qwen/Qwen1.5-0.5B-Chat 模型直接通过 transformers 进行部署。
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
pt_device = torch.device("cpu")
pt_model_name = "Qwen/Qwen1.5-0.5B-Chat"
pt_model = AutoModelForCausalLM.from_pretrained(
pt_model_name,
torch_dtype="auto",
device_map="auto"
)
pt_tokenizer = AutoTokenizer.from_pretrained(pt_model_name)
sys_content = "You are a helpful assistant and also a senior expert in the traditional Chinese medicine industry. You are very willing to provide me with detailed opinions to help me grow."
def pt_model_input(messages):
text = pt_tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
return pt_tokenizer([text], return_tensors="pt").to(pt_device)
def pt_transfor_msg(messages):
start_time = time.time()
response_text = ''
try:
model_inputs = pt_model_input(messages)
generated_ids = pt_model.generate(model_inputs.input_ids,max_new_tokens=1024)
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response_text = pt_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
except Exception as e:
print(f"Error: {e}")
finally:
execution_time = time.time() - start_time
print(f">>> function pt_transfor_msg totally use {execution_time} seconds")
return response_text
_ = pt_transfor_msg([{"role": "user", "content": "Hello"}])
def pt_qwen_text(prompt):
messages = [
{"role": "system", "content": sys_content},
{"role": "user", "content": prompt}
]
return pt_transfor_msg(messages)
if __name__ == '__main__':
prompt = "中医药理论是否能解释并解决全身乏力伴随心跳过速的症状?"
response = pt_qwen_text(prompt)
print(">>> "+response)
这段代码跟之前的代码没有太大的区别,还是用一般的 chat 模型,但是为了加快响应速度,这里预先做了一次'提问'预热。
(transformer) (base) MacBook-Pro:python user$ /Users/user/anaconda3/envs/transformer/bin/python /Users/user/Documents/code_space/git/processing/python/tcm_assistant/learning/local_model.py
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
>>> function pt_transfor_msg totally use 30.924490928649902 seconds
>>> 中医药理论中的一些概念,如阴阳五行、脏腑经络等,可能在理解这些症状的根源上有一定的帮助。但是,具体的病因和治疗方案需要通过中医医生的专业判断来确定。
一般来说,全身乏力伴心跳过速可能是由于多种原因引起的,包括心肌梗死、心脏疾病、高血压、心脏病发作等。因此,中医理论不能简单地应用到所有的病症上,只能提供一些基本的诊断和治疗方法。
如果想要找出具体的病因,可以考虑通过检查血液中的糖水平、血压、血脂等指标,或者通过专业的医疗影像学检查,如心电图、X 光片等。如果诊断结果显示没有心脏问题,那么可能是由其他原因引起的心力衰竭或糖尿病等慢性病所导致。
总的来说,虽然中医理论在一定程度上可能有助于理解一些疾病的发病机制,但并不是所有的问题都可以用中医方法解决。同时,中医治疗通常需要个体化的调整,不能代替药物治疗。
耗时 30 秒,通过缩减模型参数的方式将响应时间缩减到原来的一半。这种方式直接用于文本生成(text-generation)还是有点勉强的,但是如果只是用来做语意分析的话因为问题不大。
此外,有尝试过使用 ctransformers 来部署 gguf 模型,结果发现并不是所有的 gguf 模型都能够正常地部署。由于一直没有尝试到想要的结果因此先暂时放弃。
3. 基于 OpenVINO 实现
OpenVINO 是一个开源工具包,用于优化和部署从云端到边缘的深度学习模型。开源公司是 Intel。详细的介绍如下我就不多说了。
OpenVINO(以下简称'vino')不能直接使用 transformers 实现,在 huggingface 中我们可以直接在 Libraries 分类中选择'OpenVINO'来筛选出别人已经编译好的模型,但是中文模型实在太少了(只有一个)。接下来给我们的就只有两条路,一个是通过 save_pretrained 先将模型下载到本地,然后再通过 OpenVINO Toolkit 进行转换。
但这样过于麻烦了,折腾到现在我只想将整个实现达到可容忍的范围内就可以了。于是我选择了另一种方案,采用 Optimum Intel 插件来调用 OpenVINO Runtime 运行推理。
先安装 optimum 插件:
pip install optimum[openvino]
Requirement already satisfied: optimum[openvino] in /Users/user/anaconda3/envs/transformer/lib/python3.11/site-packages (1.19.1)
...
Successfully installed Deprecated-1.2.14 about-time-4.2.2 alive-progress-3.1.5 autograd-1.6.2 cma-3.2.1 contourpy-1.2.1 cycler-0.12.1 fonttools-4.51.0 future-1.0.0 grapheme-0.6.0 jsonschema-4.22.0 jsonschema-specifications-2023.12.1 jstyleson-0.0.2 kiwisolver-1.4.5 markdown-it-py-3.0.0 matplotlib-3.8.4 mdurl-0.1.2 natsort-8.4.0 ninja-1.11.1.1 nncf-2.10.0 openvino-2024.1.0 openvino-tokenizers-2024.1.0.0 pydot-2.0.0 pygments-2.18.0 pymoo-0.6.1.1 pyparsing-3.1.2 referencing-0.35.1 rich-13.7.1 rpds-py-0.18.1 scikit-learn-1.4.2 tabulate-0.9.0 threadpoolctl-3.5.0 tiktoken-0.6.0 wrapt-1.16.0
由于在其他尝试的时候已经将部分依赖安装了,所以整个 optimum 安装非常的快。接下来就可以编写调用代码了:
import time
import torch
from optimum.intel.openvino import OVModelForCausalLM
from transformers import AutoModelForCausalLM, AutoTokenizer
pt_model_name = "Qwen/Qwen1.5-0.5B-Chat"
sys_content = "You are a helpful assistant and also a senior expert in the traditional Chinese medicine industry. You are very willing to provide me with detailed opinions to help me grow."
if torch.cuda.is_available():
pt_device = torch.device("cuda")
else:
pt_device = torch.device("cpu")
def opt_init_model():
global opt_model, opt_tokenizer
opt_model = OVModelForCausalLM.from_pretrained(
pt_model_name,
export=True,
trust_remote_code=True,
offload_folder="offload",
offload_state_dict=True,
torch_dtype="auto",
device_map="auto"
)
opt_tokenizer = AutoTokenizer.from_pretrained(pt_model_name)
_ = opt_transfor_msg([{"role": "user", "content": "Hello"}])
def opt_model_input(messages):
text = opt_tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
model_inputs = opt_tokenizer([text], return_tensors="pt").to(pt_device)
input_ids = opt_tokenizer.encode(text, return_tensors='pt')
attention_mask = torch.ones(input_ids.shape, dtype=torch.long, device=pt_device)
return model_inputs, attention_mask
def ():
start_time = time.time()
response_text =
:
model_inputs, attention_mask = opt_model_input(messages)
generated_ids = opt_model.generate(
model_inputs.input_ids,
attention_mask=attention_mask,
max_new_tokens=,
pad_token_id=opt_tokenizer.eos_token_id
)
generated_ids = [output_ids[(input_ids):] input_ids, output_ids (model_inputs.input_ids, generated_ids)]
response_text = opt_tokenizer.batch_decode(generated_ids, skip_special_tokens=)[]
Exception e:
()
:
execution_time = time.time() - start_time
()
response_text
():
messages = [
{: , : sys_content},
{: , : prompt}
]
opt_transfor_msg(messages)
__name__ == :
prompt =
opt_init_model()
response = opt_qwen_text(prompt)
(+response)
以下是执行的情况:
INFO:nncf:NNCF initialized successfully. Supported frameworks detected: torch, onnx, openvino
/Users/user/anaconda3/envs/transformer/lib/python3.11/site-packages/bitsandbytes/cextension.py:34: UserWarning: The installed version of bitsandbytes was compiled without GPU support. 8-bit optimizers, 8-bit multiplication, and GPU quantization are unavailable.
warn("The installed version of bitsandbytes was compiled without GPU support. "
'NoneType' object has no attribute 'cadam32bit_grad_fp32'
Framework not specified. Using pt to export the model.
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
Using framework PyTorch: 2.1.2
Overriding 1 configuration item(s)
- use_cache -> True
Compiling the model to CPU ...
>>> function opt_transfor_msg totally use 0.9080860614776611 seconds
>>> function opt_transfor_msg totally use 12.55846905708313 seconds
>>> 中医药理论认为,全身乏力伴随心跳过速的症状可能与多种因素有关,包括体质、环境、疾病等。以下是一些可能的原因:
1. 身质因素:体质虚弱的人群,如老年人、慢性疾病患者、免疫力低下的人等,可能会出现全身乏力、心跳过速等症状。
2. 环境因素:环境因素如过度劳累、情绪波动、饮食不规律等,也可能导致全身乏力、心跳过速等症状。
3. 疾病因素:某些疾病,如心脏病、糖尿病、高血压等,可能会导致全身乏力、心跳过速等症状。
4. 其他因素:如药物副作用、药物过敏、药物滥用等,也可能导致全身乏力、心跳过速等症状。
因此,中医理论不能简单地解释并解决全身乏力伴随心跳过速的症状,需要结合具体的体质、环境、疾病等多方面因素进行综合分析和治疗。同时,中医治疗也强调调整生活习惯,如保持良好的饮食习惯、规律的作息、适量的运动等,以改善身体状况。
通过使用 vino 居然将响应速度提升到 13 秒内。又在 transformers 的基础上提升了 50% 以上,在只有纯 CPU 资源的情况下还算是可以的了。但我又稍微将代码进行以下调整:
def opt_model_input(messages):
text = opt_tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
model_inputs = opt_tokenizer(text, return_tensors="pt", padding=True, truncation=True).to(pt_device)
return model_inputs
def opt_transfor_msg(messages):
start_time = time.time()
response_text = ''
try:
model_inputs = opt_model_input(messages)
generated_ids = opt_model.generate(
model_inputs.input_ids,
attention_mask=model_inputs.attention_mask,
max_new_tokens=512,
num_beams=1,
pad_token_id=opt_tokenizer.eos_token_id
)
response_text = opt_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
except Exception as e:
print(f"Error: {e}")
finally:
execution_time = time.time() - start_time
print(f">>> function opt_transfor_msg totally use {execution_time} seconds")
return response_text
执行的效果如下:
Compiling the model to CPU ...
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
>>> function opt_transfor_msg totally use 0.9006850719451904 seconds
>>> function opt_transfor_msg totally use 11.58049988746643 seconds
>>> system
You are a helpful assistant and also a senior expert in the traditional Chinese medicine industry. You are very willing to provide me with detailed opinions to help me grow.
user
中医药理论是否能解释并解决全身乏力伴随心跳过速的症状?
assistant
中医药理论认为,全身乏力伴随心跳过速的症状可能与多种因素有关,包括体质、环境、疾病等。以下是一些可能的原因:
1. 身质因素:体质虚弱的人群,如老年人、慢性疾病患者、免疫力低下的人等,可能会出现全身乏力、心跳过速等症状。
2. 环境因素:环境因素如过度劳累、情绪波动、饮食不规律等,也可能导致全身乏力、心跳过速等症状。
3. 疾病因素:某些疾病,如心脏病、糖尿病、高血压等,可能会导致全身乏力、心跳过速等症状。
4. 其他因素:如药物副作用、药物过敏、药物滥用等,也可能导致全身乏力、心跳过速等症状。
因此,中医理论不能简单地解释并解决全身乏力伴随心跳过速的症状,需要结合具体的体质、环境、疾病等多方面因素进行综合分析和治疗。同时,中医治疗也强调调整生活习惯,如保持良好的饮食习惯、规律的作息、适量的运动等,以改善身体状况。
可以将执行时间压缩到 12 秒内。至此,基于 Intel 的 CPU Only 方案基本上结束了。
总结
由于最终也是使用 Qwen/Qwen1.5-0.5B-Chat 模型,因此就以该模型进行一下总结。为此我又用 ollama 重新下载了 Qwen/Qwen1.5-0.5B-Chat 进行对比。
在 ollama 中重新调用发现只需要 4 秒就完成了输出,但是回答的内容就相当敷衍。vino 方案中输出的结果明显比 ollama 方案数据的结果要来得完整,但是 0.5B 模型输出的效果我觉得 ollama 的输出才算是正常的(毕竟 0.5B 参数少不能要求太高,而 vino 方案输出的感觉更超越上面提到的 14b-chat-q4_K_M 的输出,难道我也出现'幻觉'了?)。
anyway,现在用 vino 方案再换个 1.8B 或者 gamme 2B 应该问题不大了吧。
综上所述,在 Mac Intel 环境下进行本地 LLM 部署时,若无法使用 GPU 加速,OpenVINO 配合 Optimum Intel 插件提供了最佳的推理性能优化方案,相比原生 Transformers 有显著提升,且能保持较好的输出质量。Ollama 虽然便捷,但在小参数量模型下可能存在输出质量下降的问题。开发者可根据实际场景在便捷性与性能之间做出权衡。