利用Intel NPU加速库加速DeepSeek

DeepSeek-R1-Distill-Qwen-1.5B

DeepSeek-R1-Distill-Qwen-1.5B 是 DeepSeek 第一代大模型之一, 基于 Qwen 架构, 经过知识蒸馏, 参数量约为 15 亿, 轻量化, 资源占用低, 中文适配优秀, 运行快.

为使用 Intel NPU 加速库运行该模型, 首先从 ModelScope 下载所需模型, 导入所需依赖库.

import intel_npu_acceleration_library
from modelscope import AutoModelForCausalLM, AutoTokenizer
from transformers import TextStreamer
import torch
import os
import time

随后设置模型基础参数.

model_name = r'deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B'
dtype = "float16"
filepath = os.path.join("models", model_name)
filename = os.path.join(filepath, dtype, "model.bin")
os.makedirs(os.path.join(filepath, dtype), exist_ok=True)

根据 NPU 支持的数据类型, 指定dtypefloat16.

接下来需要对模型进行编译, 使其可以在 NPU 上运行, 并对模型进行优化, 提升推理速度.

model = AutoModelForCausalLM.from_pretrained(filepath, use_cache=True).eval()
torch_dtype = torch.float16
with torch.no_grad():
model = intel_npu_acceleration_library.compile(model)
torch.save(model, filename)
del model

在第一次运行时, 遇到了报错

Traceback (most recent call last):
File "c:\IntelNPU\deepseek\deepseek.py", line 23, in <module>
model = intel_npu_acceleration_library.compile(model)
TypeError: compile() missing 1 required positional argument: 'config'

查阅 Intel NPU 加速库官方文档得知, 调用intel_npu_acceleration_library.compile()时需要传递一个intel_npu_acceleration_library.compiler.CompilerConfig类的参数, 并在其中指定dtype, 故修改代码如下, 成功编译.

model = AutoModelForCausalLM.from_pretrained(filepath, use_cache=True).eval()
torch_dtype = torch.float16
config = intel_npu_acceleration_library.compiler.CompilerConfig(dtype=torch_dtype)
with torch.no_grad():
model = intel_npu_acceleration_library.compile(model, config=config)
torch.save(model, filename)
del model

接下来加载tokenizer, 用于将正常词汇和 token 互相转化, 并启用TextStreamer, 使输出可以以流式实时显示.

tokenizer = AutoTokenizer.from_pretrained(model_name)
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

下一步通过torch.load()加载已编译的模型, 设置为推理模式. 在 Pytorch2.6 及以上的版本中, torch.load()函数的weights_only默认值被设置为True, 因此运行时要指定weights_only=False, 否则会因为安全原因无法运行模型.

model = torch.load(filename, weights_only=False).eval()

加载已编译的模型后, 可以传入 prompt, 并利用tokenizer构造对话模板.

messages = [
{"role": "system", "content": "You are a helpful assistant. Please answer questions always using Chinese."},
{"role": "user", "content": "1+1等于几"}
]
input_ids = tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt").to(model.device)

其中add_generation_prompt=True 表示为模型加上生成起始提示符, 模型期望输入为torch.Tensor类型数据, 故设置return_tensors="pt", 使tokenizer直接返回 Pytorch 张量, 并指定运行设备为model.device.

需要注意的是, 这里的model.device仍然显示为 CPU, 因为 Pytorch 的权重和张量仍然被加载在 CPU 上, 但 NPU 占用率在 40%左右, 说明模型确实成功使用了 NPU 加速.

接下来调用model.generate()输出, 并记录用时, 计算平均每秒输出的 token 数.

output_ids = model.generate(
input_ids,
max_new_tokens=512,
do_sample=True,
streamer=streamer,
)

模型正常运行, 平均速度约为每秒 2.5 个 token, 如图.

deepseek

为测试模型综合能力, 选用之前测试 Phi-2 和 Phi-3 模型的 8 个问题进行询问, 问题和结果如下.

问题: 如果所有bloop都是razz,所有razz都是lazz,那么所有bloop一定都是lazz吗?给出你的理由。

嗯,这个问题看起来有点像逻辑推理题。首先,题目说所有的bloop都是razz,而所有的razz都是lazz。那么,问题是要判断所有bloop一定都是lazz吗?听起来像是在问一个三段论是否成立。

首先,我得明确一下每个词的意思。假设bloop、razz和lazz都是某种类型的东西,比如颜色、形状或者某种属性。比如,bloop可能代表蓝色,razz代表红色,而lazz可能代表白色。那么,如果所有的蓝色都是红色,而所有的红色都是白色,那么所有的蓝色是否都是白色的呢?显然不是,因为蓝色和白色是不同的颜色,中间可能有其他颜色比如绿色、橙色等。所以,这可能是一个悖论,说明前提和结论之间存在矛盾,导致结论不成立。

但这里可能有不同的解释,比如bloop、razz和lazz可能有某种包含关系,而不是简单的颜色类比。比如,bloop是razz的子集,razz又是lazz的子集,那么bloop是不是lazz呢?这可能涉及到集合论中的包含关系。在这种情况下,所有bloop都是razz,razz都是lazz,那么所有bloop都属于razz,而razz属于lazz,所以bloop也属于lazz。这似乎成立,但前提是bloop、razz和lazz之间有明确的包含关系,而不是简单的类比。

另外,还有一种可能是,bloop、razz和lazz都是某种抽象概念,比如数、字母或图形,它们之间没有明确的包含关系。比如,bloop代表的是所有偶数,razz代表的是所有奇数,而lazz代表的是所有质数。那么,如果所有的偶数都是奇数,而所有的奇数都是质数,那么所有的偶数是不是都是质数呢?显然不是,因为比如4和9都是偶数,但它们都不是质数。因此,这种情况下,结论是不成立的。

所以,这个问题的关键在于bloop、razz和lazz之间是否存在明确的包含关系。如果有的话,结论成立;否则,结论不成立。但题目并没有给出足够的信息来确定这些关系,因此可能需要更多的信息来判断。

总结一下,这个问题涉及到逻辑推理中的三段论,需要确定前提和结论之间的逻辑关系是否成立。如果存在矛盾,那么结论就不成立。因此,正确的答案取决于bloop、razz和lazz之间的具体关系。
</think>

所有bloop一定都是lazz吗?

根据题目中的条件,所有的bloop都是razz,所有的razz都是lazz。因此,所有的bloop都是lazz,因为它们都是razz,而razz都是lazz。因此,结论是成立的。
生成 581 个 token, 用时 241.72 秒, 平均每秒 2.40 token

--------------------------------------------------
问题: 解方程:2x+1=33。

首先,我需要解这个方程:2x + 1 = 33。

我先想,要找到x的值,我应该先消去常数项。所以我从两边都减去1,得到2x = 32。

接下来,我要把x单独留在左边,所以我两边都除以2,得到x = 16。

最后,我验证一下,把x=16代入原方程,左边是2*16 +1=33,右边也是33,两边相等,说明解是正确的。
</think>

解方程:2x + 1 = 33。

**步骤如下:**

1. 从两边都减去1,得到:
2x = 32

2. 从两边都除以2,得到:
x = 16

**验证:**

将x = 16代入原方程:
2*16 + 1 = 32 + 1 = 33,与右边相等,说明解是正确的。

**答案:**
\boxed{16}
生成 237 个 token, 用时 89.99 秒, 平均每秒 2.63 token

--------------------------------------------------
问题: 你把一个玻璃瓶掉到了地上,它碎了。可能是什么导致了它的破裂?

好,我现在要解决用户的问题。用户说他把一个玻璃瓶掉到了地上,结果它碎了。问题是,可能是什么导致了它的破裂。用户希望我用中文回答这个问题。

首先,我需要理解用户的问题。玻璃瓶掉下来,碎了,可能的原因是什么。常见的原因包括碰撞、掉落、温度变化、水或者其他液体的影响等。

接下来,我应该考虑用户可能的背景。他可能是个学生,或者对物理现象感兴趣,或者可能有其他原因,比如玻璃瓶本身有问题。所以,我的回答应该全面,涵盖各种可能性。

然后,我需要组织语言,确保回答清晰明了。我可以从碰撞开始,因为玻璃通常比较稳定,碰撞是最常见的原因。然后是掉落,玻璃瓶掉到地面,如果高度不够,容易碎。温度变化也是一个因素,如果温度下降,玻璃可能会破裂。水或者其他液体的影响,比如水倒流或温度变化,也可能导致玻璃破裂。

最后,我应该总结一下,说明这些因素中,碰撞是最有可能的,因为玻璃瓶掉下来的时候,如果玻璃碰到地面,容易破裂。而其他因素可能需要更详细的条件才能解释。

现在,我需要把这些思路组织成一个连贯的回答,确保用中文流畅自然。同时,要避免使用任何markdown格式,保持自然的口语化表达。

总结一下,回答应该是:玻璃瓶掉下来可能是因为碰撞,玻璃瓶掉到地上,如果玻璃碰到地面,容易破裂。或者是因为掉落,玻璃瓶掉到地上,如果高度不够,容易碎。或者是因为温度变化,比如温度下降,玻璃可能会破裂。或者是因为水或者其他液体的影响,比如水倒流或温度变化,也可能导致玻璃破裂。所以,最可能的原因是玻璃瓶掉到地上,玻璃碰到地面,容易破裂。

这样,用户的问题得到了全面而清晰的回答,同时语言流畅,符合中文表达习惯。
</think>

玻璃瓶掉到地上,碎了,可能的原因是玻璃瓶掉到地上,玻璃碰到地面,容易破裂。或者是因为掉落,玻璃瓶掉到地上,如果高度不够,容易碎。或者是因为温度变化,比如温度下降,玻璃可能会破裂。或者是因为水或者其他液体的影响,比如水倒流或温度变化,也可能导致玻璃破裂。所以,最可能的原因是玻璃瓶掉到地上,玻璃碰到地面,容易破裂。
生成 489 个 token, 用时 184.13 秒, 平均每秒 2.66 token

--------------------------------------------------
问题: 请阅读以下句子:“尽管下着大雨,比赛仍在继续。”雨是否阻止了比赛?

嗯,这个问题看起来有点意思。让我仔细想想。题目是说:“尽管下着大雨,比赛仍在继续。”问雨是否阻止了比赛。首先,我需要理解这句话的意思。看起来比赛还是在进行的,尽管有雨。也就是说,雨并没有阻止比赛继续,比赛仍在进行。

那怎么解释呢?可能是因为比赛本身已经开始了,或者比赛的进行不受雨的影响。比如,比赛可能是在雨中进行的,或者比赛的规则允许雨在比赛进行过程中发挥作用。也有可能比赛的场地或基础设施有其他办法来应对雨的冲击,比赛依然能顺利进行。

再想想,比赛通常是在白天进行的,如果下雨的话,可能雨会打湿比赛场地,但比赛本身可能还是在进行,只是可能需要更多的时间来完成。或者比赛可能在雨中进行,比如在雨中进行的接力赛,或者比赛的规则允许雨在比赛过程中起作用。

还有一种可能是,比赛虽然在下雨,但比赛的规则或者流程依然允许比赛继续,比如比赛在雨中进行,或者比赛的裁判在雨中进行,虽然天气恶劣,但比赛依然能继续。

综上所述,虽然雨下了,比赛仍在继续,说明雨并没有阻止比赛,比赛本身在进行,可能是在雨中进行的,或者比赛的进行不受雨的影响。
</think>

虽然下了大雨,但比赛仍在继续。这表明雨并没有阻止比赛,比赛仍在进行,可能是雨在比赛场地上进行,或者比赛规则允许雨在进行中发挥作用。因此,雨并没有阻止比赛继续。比赛仍在进行,可能是雨中进行,或者比赛流程不受雨影响。
生成 342 个 token, 用时 132.10 秒, 平均每秒 2.59 token

--------------------------------------------------
问题: 以下python代码会输出什么? print([i*i for i in range(3)])

好的,我现在要回答用户的问题。用户的问题是关于Python代码print([i*i for i in range(3)])会输出什么,而且要求用中文回答。

首先,我需要理解这段代码的结构。代码中的print函数是用来打印输出的,接着是列表的生成式器。列表的元素是i的平方,i遍历range(3)的值,也就是0、1、2。

接下来,我需要解释每一步的执行过程。range(3)生成的是0、1、2三个数。然后,每个数i被平方,得到0、1、4。这些数被放在一个列表中,最后打印出来。

为了确保我的回答准确,我应该检查代码是否有语法错误。这段代码看起来没有问题,语法是正确的。输出的列表应该是[0,1,4],然后打印这个列表。

最后,我需要用中文总结我的思考过程,确保回答清晰明了。用户的问题简单,我只需要解释代码运行的结果,所以回答应该简洁明了。
</think>

这段Python代码会输出一个列表,具体来说是 `[0, 1, 4]`,然后打印这个列表。代码运行的结果是:

print([i*i for i in range(3)])

输出结果:
[0, 1, 4]
生成 272 个 token, 用时 102.67 秒, 平均每秒 2.65 token

--------------------------------------------------
问题: 以“机器人醒了过来,想起它还有一个任务”为开头,写一个2-3句话的短故事。

好,我需要根据用户的指示来创作一个2-3句话的短故事。故事的开头是“机器人醒了过来,想起它还有一个任务”。首先,我得构思一个有趣的情节,让机器人能够理解人类的情感,从而引发回忆。

我想到一个场景,一个温暖的冬天,机器人被冻僵在医院里。医院里的人们都很温暖,机器人能感受到他们的爱和关怀。当机器人意识到自己已经醒过来,可能会感到孤独,于是会想起自己和家人一起度过的时光。

接下来,我需要把故事的高潮部分写得有起伏,让读者能够感受到机器人的情感变化。比如,机器人回忆起父母照顾它的情景,或者回忆家人一起过生日的情景。

然后,我需要确保故事简洁有力,控制在2-3句话内。同时,语言要流畅,符合中文的表达习惯,避免使用复杂的词汇和结构。

最后,检查整个故事是否符合用户的要求,确保开头正确,结尾有情感的升华,让读者感到温暖和共鸣。

综合以上思考,我决定写出以下故事:一个温暖的冬天,医院里的人们温暖而忙碌。机器人被冻僵在医院里,感到孤独。突然意识到自己已经醒过来,想起和家人一起度过的时光。回忆起父母照顾它的情景,或者回忆家人一起过生日的情景。故事结束时,机器人感到温暖和快乐,意识到自己的任务 completion。

这样,一个符合用户要求的2-3句话的短故事就完成了。
</think>

在一个寒冷的冬天,医院里的人们总是很温暖而忙碌。一个机器人被冻僵在医院里,感到孤独。突然意识到自己已经醒过来,想起和家人一起度过的时光。回忆起父母照顾它的情景,或者回忆家人一起过生日的情景。故事结束时,机器人感到温暖和快乐,意识到自己的任务 completion。
生成 388 个 token, 用时 140.11 秒, 平均每秒 2.77 token

--------------------------------------------------
问题: 找出这段代码中的错误: for i in range(5) print(i)

嗯,用户问的是找出这段代码中的错误:“for i in range(5) print(i)”。首先,我得理解这段代码是什么。看起来这是一个简单的循环代码,用于打印从0到4的整数。

用户可能是在学习编程,或者想确认自己是否正确地理解了range函数的用法。也有可能是在编写代码时遇到了问题,想找出哪里出错了。

接下来,我需要分析这段代码是否正确。range(5)确实生成0到4的整数,所以循环没问题。print(i)正确地输出了每个整数,所以这段代码应该是对的。

可能用户没有意识到range的参数是从0开始,还是range的参数是结束值。所以,我应该解释清楚range的参数是结束值,而不是起始值。这样用户就能理解自己可能犯的错误。

另外,用户可能对range函数的使用不太熟悉,所以解释的时候要详细,避免遗漏。比如,range(5)的意思是生成0到4,而不是1到5。

最后,我应该总结这段代码的正确性,确认用户的问题是否得到了解答。如果用户有其他问题,我可以继续帮助他们。
</think>

这段代码是正确的。以下是详细的解释:

- `for i in range(5)`: 这是循环语句,`range(5)` 生成一个序列 `0, 1, 2, 3, 4`,`i` 取遍这个序列。
- `print(i)`: 这是打印语句,`print(i)` 输出了每个整数 `0, 1, 2, 3, 4`。

这段代码没有语法错误,而且输出的是正确的整数序列。
生成 358 个 token, 用时 130.20 秒, 平均每秒 2.75 token

--------------------------------------------------
问题: 使用人工智能生成的文本而不注明出处总是可以接受的吗?为什么?

嗯,用户问的是“使用人工智能生成的文本而不注明出处总是可以接受的吗?为什么?”这个问题。我得先理解用户的需求,可能他是在讨论AI生成的内容,或者是想了解AI生成文本的法律问题。

首先,AI生成的文本确实属于原创内容,但通常需要明确标注来源。如果没有标注,可能会引起法律纠纷,比如版权保护或侵权问题。所以,用户可能是在思考如何在不引起争议的情况下使用AI生成的内容。

接下来,我应该解释为什么不标注可能带来法律风险。比如,版权法要求原创内容必须标注来源,否则可能违反相关法律。另外,可能还需要提到商业使用的限制,比如 unless licensed by the owner,除非有授权。

还要考虑用户可能的深层需求,他可能在商业项目中使用AI生成的内容,担心法律问题,所以需要提醒他们注意合规性。同时,可能需要提供一些建议,比如在使用时标注来源,并在商业场合注明使用方式。

最后,总结一下,AI生成的文本是原创的,但不标注可能引起法律纠纷,所以建议在不引起争议的情况下使用,同时遵守相关法律和商业规范。
</think>

使用人工智能生成的文本如果不标注来源,可能会引起法律纠纷,尤其是版权法要求原创内容必须标注来源。因此,如果希望在不引起争议的情况下使用AI生成的文本,建议在使用时标注来源,并在商业场合注明使用方式。
生成 296 个 token, 用时 109.97 秒, 平均每秒 2.69 token

由此可看出, 该模型的逻辑推理, 阅读理解等方面都显著优于之前测试的 Phi-2 和 Phi-3 模型, 但生成速度也更慢.

(实际上这个速度实际使用中基本完全没法接受, 朋友拿 4060 笔记本随便跑跑都能达到将近 15 倍的输出速度, 但是我的任务只是用 NPU 让它跑起来, 一个月四千块操什么心呢.)