Image 10

在本文中,我们将介绍如何从 HuggingFace 选择任何现成的模型并在 Google Collaboratory 上托管它。本文假设您熟悉 Jupyter Notebook,如果您不熟悉,可以在此处轻松学习。最终的 Jupyter Notebook 在文章底部。

模型选择

首先,我们将从 HuggingFace 选择一个模型;由于我们将使用 llama.cpp 在 GPU 上利用模型,我们必须在 GGUF 格式中选择模型。通常,主要的贡献者是 TheBloke,他将模型从 .bin 格式转换为 .GGUF 格式,以便我们可以在消费级 GPU 上更高效地运行它。在本文中,我们将使用 LLaMA 2 7B 模型

Google Colaboratory 设置

Colab 是一项托管的 Jupyter Notebook 服务,无需设置即可使用,并提供对计算资源的免费访问,包括 GPU 和 TPU。创建 .ipynb 文档后,不要忘记转到 “Runtime” -> “Change runtime type” -> “T4 GPU”。 这将允许您的 notebook 访问 GPU。

我们将首先创建一个新单元格并构建 LLaMA.cpp 依赖项。由于我们将使用 Jupyter Notebook,我们必须使用 LLaMA-cpp-python 端口,以便我们能够访问 GPU。

!CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python

运行该命令将构建所有必要的工具,以便我们的代码能够进行 GPU 加速

现在我们在另一个单元格中安装所有代码依赖项:

!pip install fastapi[all] uvicorn python-multipart transformers pydantic tensorflow

由于环境位于 Google Colab 服务器上的临时会话中,如果我们想访问它,我们将不得不使用 Ngrok 将本地地址端口转发到公共地址。

前往 https://dashboard.ngrok.com/signup 创建一个帐户并获取您的 API 密钥。

让我们使用以下命令将 Ngrok 下载并解压缩到我们的实例中:

!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
!unzip -o ngrok-stable-linux-amd64.zip

我们还必须将我们的 API 密钥添加到服务器实例:

!./ngrok authtoken <YOUR_NGROK_API_TOKEN>

创建服务器

为了创建一个服务器文件,我们将使用 Fast API 作为我们的 HTTP 库。我们还需要将模型下载到我们的 GPU,并让 LLaMA-cpp-python 能够访问 GPU 和模型,使用 API 我们可以使用 /generate 文本来调用我们的 LLaMA 模型。

%%writefile app.py
from typing import Any
from fastapi import FastAPI
from fastapi import HTTPException
from pydantic import BaseModel
from huggingface_hub import hf_hub_download
from llama_cpp import Llama
import tensorflow as tf

# GGML 模型是必需的,以便在 T4 GPU 上适配 Llama2-13B

GENERATIVE_AI_MODEL_REPO = "TheBloke/Llama-2-7B-GGUF"
GENERATIVE_AI_MODEL_FILE = "llama-2-7b.Q4_K_M.gguf"

model_path = hf_hub_download(
    repo_id=GENERATIVE_AI_MODEL_REPO,
    filename=GENERATIVE_AI_MODEL_FILE
)

llama2_model = Llama(
    model_path=model_path,
    n_gpu_layers=64,
    n_ctx=2000
)

# 测试一个推理
print(llama2_model(prompt="Hello ", max_tokens=1))

app = FastAPI()

# 这定义了端点预期的数据 json 格式,根据需要更改
class TextInput(BaseModel):
    inputs: str
    parameters: dict[str, Any] | None

@app.get("/")
def status_gpu_check() -> dict[str, str]:
    gpu_msg = "Available" if tf.test.is_gpu_available() else "Unavailable"
    return {
        "status": "I am ALIVE!",
        "gpu": gpu_msg
    }

@app.post("/generate/")
async def generate_text(data: TextInput) -> dict[str, str]:
    try:
        print(type(data))
        print(data)
        params = data.parameters or {}
        response = llama2_model(prompt=data.inputs, **params)
        model_out = response['choices'][0]['text']
        return {"generated_text": model_out}
    except Exception as e:
        print(type(data))
        print(data)
        raise HTTPException(status_code=500, detail=len(str(e)))

如果您想使用不同的模型而不是 LLaMA 2,您只需要更改 “GENERATIVE_AI_MODEL_REPO” 和 “GENERATIVE_AI_MODEL_FILE”。 “GENERATIVE_AI_MODEL_REPO” 是 HuggingFace 的直接仓库名称。“GENERATIVE_AI_MODEL_FILE” 是您想要使用的特定模型文件,您可以在页面中间找到它,具体取决于您想要的用例,通常,我选择推荐的 “medium, balanced quality”。

以下代码将启动服务器,并向您反馈已运行的时间(最长 10 分钟),命令日志文件也会导出到左侧 “Google Colabs Files” 中的 server.log 中:

# 服务器将启动模型下载,启动需要一段时间
# 如果尚未下载,则大约需要 5 分钟
import subprocess
import time

from ipywidgets import HTML
from IPython.display import display

t = HTML(
    value="0 Seconds",
    description = 'Server is Starting Up... Elapsed Time:' ,
    style={'description_width': 'initial'},
)
display(t)

flag = True
timer = 0

try:
    subprocess.check_output(['curl',"localhost:8000"])
    flag = False
except:
    get_ipython().system_raw('uvicorn app:app --host 0.0.0.0 --port 8000 > server.log 2>&1 &')

res = ""

while(flag and timer < 600):
  try:
    subprocess.check_output(['curl',"localhost:8000"])
  except:
    time.sleep(1)
    timer+= 1
    t.value = str(timer) + " Seconds"
    pass
  else:
    flag = False

if(timer >= 600):
  print("Error: timed out! took more then 10 minutes :(")
subprocess.check_output(['curl',"localhost:8000"])

测试我们的 API

为了测试我们的 API,我们必须使用 Ngrok 将服务器 localhost 对外开放,并访问 “/generate” 端点。

以下代码将获取当前的 localhost,并打印出 API URL:

# 这将启动 Ngrok 并创建公共 URL
import subprocess
import time
import sys
import json
from IPython import get_ipython
get_ipython().system_raw('./ngrok http 8000 &')
time.sleep(1)
curlOut = subprocess.check_output(['curl',"http://localhost:4040/api/tunnels"],universal_newlines=True)
time.sleep(1)
ngrokURL = json.loads(curlOut)['tunnels'][0]['public_url']
%store ngrokURL
print(ngrokURL)

我们的 API 驱动代码如下:

import requests
# 定义 FastAPI 端点的 URL
%store -r ngrokURL
# 定义要在 POST 请求中发送的数据
data = {
  "inputs": '''
Write an SQL Statement to find number of rows in a table
''',
  # paramaters 可以在这里找到 https://abetlen.github.io/llama-cpp-python/#llama_cpp.llama.Llama.create_completion
  "parameters": {"temperature":0.1,
                 "max_tokens":200}
  # temperature 越高,响应越有创造性,越低则越精确
  # max_token 是允许生成的最大 (简化) "单词" 数量
}

# 发送 POST 请求
response = requests.post(ngrokURL + "/generate/", json=data)

# 检查响应
if response.status_code == 200:
    result = response.json()
    print("Generated Text:\n", data["inputs"], result["generated_text"].strip())
else:
    print("Request failed with status code:", response.status_code)

这将使用我们提供的 prompt 并调用我们创建的 API,我们可以自由更改输入和参数。

总结思考

这个项目非常有趣,因为它不是每天都能启动一个实例并托管一个模型供您的应用程序调用。本文使这样做变得非常容易。我已在此处附上 notebook 链接