全参数模型加载
调用模型代码-qwen_1.5-7B为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| from transformers import AutoModelForCausalLM, AutoTokenizer import torch from fastapi import FastAPI, Depends from pydantic import BaseModel import uvloop from fastapi.middleware.cors import CORSMiddleware uvloop.install()
device = "cuda"
model_name = "output/firefly-qwen-7b-sft-full" model = AutoModelForCausalLM.from_pretrained( model_name, low_cpu_mem_usage=True, torch_dtype=torch.float16, device_map='auto' )
tokenizer = AutoTokenizer.from_pretrained(model_name)
class MakeConversation: def __init__(self): self.max_new_tokens = 1024 self.do_sample = False self.temperature = 0.1 self.repetition_penalty = 1.0
def conversation(self, query): stop_token_id = tokenizer.encode('<|im_end|>', add_special_tokens=False) assert len(stop_token_id) == 1 stop_token_id = stop_token_id[0]
prompt = f"""{query}"""
messages = [ {"role": "user", "content": prompt} ] text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) model_inputs = tokenizer([text], return_tensors="pt").to(device)
generated_ids = model.generate( model_inputs.input_ids, max_new_tokens=self.max_new_tokens, temperature=self.temperature, repetition_penalty=self.repetition_penalty, do_sample=self.do_sample, eos_token_id=stop_token_id ) generated_ids = [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
return response
app = FastAPI()
app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
class Query(BaseModel): query: str
make_conversition = Depends(MakeConversation)
@app.post("/conversation/") async def conversation(query: Query, conv: MakeConversation = make_conversition): print("输入'exit'或'quit'来退出服务器部署。") while True: if query.query.lower() == 'exit' or query.query.lower() == 'quit': print("退出服务。") break response = conv.conversation(query.query) return {"response": response}
|
uvloop ,只需在使用FastAPI之前安装uvloop即可
使用 uvloop 可以显著提高异步 I/O 操作的性能,特别适合网络密集型应用。在项目中安装和使用 uvloop 非常简单,只需要调用 uvloop.install(),并确保在应用启动之前完成安装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| from fastapi import FastAPI import uvloop
uvloop.install()
app = FastAPI()
@app.get("/") async def read_root(): return {"message": "Hello, World!"}
@app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None): return {"item_id": item_id, "q": q}
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
|
在模型进行Next Token Prediction的时候,do_sample参数指:
do_sample 参数在文本生成过程中决定了是否使用采样方法来生成文本。具体来说,它控制模型在生成下一个 token 时的选择策略。
**do_sample 参数的作用:**
1. **do_sample=False(默认值)**:
• 当 do_sample 被设置为 False 时,模型使用贪婪搜索(Greedy Search)策略生成文本。
• 贪婪搜索每一步都选择概率最高的下一个 token。这种方法确保生成的文本是概率最大的序列。
• 贪婪搜索的结果是确定性的,同样的输入总是会得到相同的输出,因为它不包含随机性。
2. **do_sample=True**:
• 当 do_sample 被设置为 True 时,模型使用采样(Sampling)策略生成文本。
• 采样策略在生成下一个 token 时,从预测的概率分布中随机选择一个 token。被选择的 token 的概率与其预测概率成正比。
• 这种方法引入了随机性,因此同样的输入可以生成不同的输出,增加了生成的多样性和创造性。
**采样策略:**
• **温度(Temperature)**:
• temperature 参数配合采样使用,可以控制采样的随机性程度。较高的温度会使采样的结果更加随机,较低的温度会使结果更加确定性。
• **Top-k 采样**:
• 在 Top-k 采样中,模型只从前 k 个概率最高的 token 中采样。这个方法可以过滤掉低概率的 token,从而提高生成文本的质量。
• **Top-p(Nucleus)采样**:
• 在 Top-p 采样中,模型从累积概率达到 p 的最小集合中采样。这个方法根据概率分布动态确定采样范围,通常比 Top-k 采样更灵活。
generarted_ids解析
1 2 3
| generated_ids = [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ]
|
1. **zip(model_inputs.input_ids, generated_ids)**:
• model_inputs.input_ids 是输入给模型的 token 序列。
• generated_ids 是模型生成的完整序列,包含输入 token 和新生成的 token。
• zip 函数将 model_inputs.input_ids 和 generated_ids 两个列表按元素配对,形成一个由元组组成的迭代器,每个元组包含一个输入序列和相应的生成序列。
2. **列表解析**:
• 列表解析用于遍历 zip 生成的元组,并从每个 output_ids(生成的序列)中去掉输入序列部分,提取新生成的部分。
3. **output_ids[len(input_ids):]**:
• 对于每个 input_ids 和 output_ids(生成的序列):
• len(input_ids) 是输入序列的长度。
• output_ids[len(input_ids):] 切片操作用于从 output_ids 中去掉前 len(input_ids) 个 token,只保留新生成的 token。
**示例**
假设我们有以下输入和生成的序列:
• 输入序列(input_ids): [1, 2, 3]
• 生成的序列(generated_ids): [1, 2, 3, 4, 5, 6]
代码将会进行如下操作:
• zip 会形成配对: [(input_ids, generated_ids)]
• 对于每个配对,output_ids[len(input_ids):] 会变成 [4, 5, 6],因为 len(input_ids) 是 3。
最终结果是一个新的 generated_ids 列表,只包含新生成的 token,而不包含输入的 token。
Depends
**Depends 函数**
• Depends 是 FastAPI 中用于声明依赖的函数。当 FastAPI 看到某个路径操作(即 API 端点)依赖某个对象时,它会自动创建和管理该依赖的实例。
• Depends 的参数是一个可调用对象,如函数或类的构造函数。
**MakeConversation 类**
假设我们有一个名为 MakeConversation 的类:
1 2 3 4 5 6 7 8 9 10
| class MakeConversation: def __init__(self): self.max_new_tokens = 1024 self.do_sample = False self.temperature = 0.1 self.repetition_penalty = 1.0
def conversation(self, query): pass
|
**make_conversition = Depends(MakeConversation)**
• Depends(MakeConversation) 告诉 FastAPI 需要创建一个 MakeConversation 类的实例。
• 这种依赖会在每次请求时被自动创建和管理。
**在路径操作中使用**
1 2 3 4
| @app.post("/conversation/") async def conversation(query: Query, conv: MakeConversation = make_conversition): response = conv.conversation(query.query) return {"response": response}
|
在上面的代码中:
1. **路径操作函数 conversation**:
• 这是一个处理 /conversation/ 路径的 POST 请求的函数。
• query 参数是一个 Query 类型的实例,包含了请求体中的数据。
• conv 参数是一个 MakeConversation 类型的实例,由 FastAPI 自动创建并注入。
2. **依赖注入**:
• conv: MakeConversation = make_conversition 这部分代码表示 conv 依赖于 MakeConversation 类的实例。
• 当这个路径操作被调用时,FastAPI 会自动创建一个 MakeConversation 实例并将其作为 conv 参数传递给路径操作函数。
async协程
async 关键字在 Python 中用于定义异步函数,通常称为协程(coroutine)。协程是一种可以在执行过程中暂停并在稍后恢复执行的函数,允许在等待某些操作完成时进行其他操作。这对于处理 I/O 操作(如网络请求、文件读取等)非常有用,因为这些操作可能会阻塞程序的执行。
1 2 3 4 5 6 7 8
| async def conversation(query: Query, conv: MakeConversation = make_conversition): print("输入'exit'或'quit'来退出服务器部署。") while True: if query.query.lower() == 'exit' or query.query.lower() == 'quit': print("退出服务。") break response = conv.conversation(query.query) return {"response": response}
|
• **async def conversation**:
• 这定义了一个异步函数 conversation。
• 异步函数在遇到 I/O 操作时不会阻塞整个程序的执行,而是允许其他任务继续执行。
**异步函数的优势**
• **非阻塞**:
• 异步函数在执行耗时操作(如 I/O 操作)时不会阻塞其他任务的执行,提高了程序的效率和响应能力。
• **提高性能**:
• 特别是在处理大量 I/O 操作时,异步函数可以显著提高程序的性能。