Qwen1.5-110B简单调用

Qwen1.5-110B 发布,官方提供了一个在线版,可以通过代码简单调用,以下是一个简单示例。

测试了一下,Jailbreak 比较简单,但一股 GPT 味,不太好玩。理解偏强吧,但做推理题还是不行。

import requests
import random
import string

base_url = 'https://qwen-qwen1-5-110b-chat-demo.hf.space'

# gen random char(11) hash
chars = string.ascii_lowercase + string.digits
session_hash = ''.join(random.choice(chars) for _ in range(11))

json_prompt = {
    'data': [
        'What is your name?', # prompt
        [
            ## chat history
            # [
            #     'What is your name?',
            #     'I am Alice. How can I assist you today?'
            # ],
        ],
        'You are Alice, a human girl.', # system prompt
    ],
    'fn_index': 0,
    'session_hash': session_hash,
}

response = requests.post(f'{base_url}/queue/join', json = json_prompt)
response = requests.get(f'{base_url}/queue/data?session_hash={session_hash}')

print(response.text)

不要把服务建在非默认端口上

最近,关于服务安全,发现一个有趣的结论——把服务建在不常用的端口上会降低而非提升安全性。比如说 MySQL 该建在 3306 就建在 3306,不要去换端口。这个主要是针对集群部署来说。

以曾经的经验,更改服务端口通常可以避免被一般工具扫描。然而,现代的网络空间测绘已经把整个网络扫了个遍。即使更换端口,这些服务仍然已经被识别并被纳入数据库。这些非默认端口的服务,反而成了某种特征。

采用同一批非常规端口的服务器,通常由同一个运维或同一套脚本部署。一旦其中一台机器有漏洞,通过端口,就可以从茫茫 IP 中筛选出所有机器,从而集中爆破。如果这些服务没有修改端口,要找到它们反倒要花更多的功夫。

总的来说,任何响应信息都不该包含具有特征的内容,以免被定位到整个集群。

【更新】2分钟,让colab给我画画

根据 Colab 的特性更新了脚本,启动时间缩短到 2 分钟左右。

# 核心部分
!wget -q -c 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64' -O cfd
!chmod a+x cfd

!pip install --prefer-binary udocker
!udocker --allow-root pull ubuntu:latest
!udocker --allow-root create --name=ubuntu ubuntu:latest
!udocker --allow-root setup --nvidia ubuntu

!pip install --prefer-binary -r https://raw.githubusercontent.com/comfyanonymous/ComfyUI/master/requirements.txt
!pip install --prefer-binary -r https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/requirements.txt

!udocker --allow-root run -v /usr --entrypoint=sh ubuntu -c "git config --global http.sslVerify false"
!udocker --allow-root run -v /usr --entrypoint=sh ubuntu -c "git clone https://github.com/comfyanonymous/Comfy\UI"
!udocker --allow-root run -v /usr --entrypoint=sh ubuntu -c "cd ComfyUI/custom_nodes; git clone https://github.com/ltdrdata/ComfyUI-Manager"
# 启动部分
!nohup ./cfd tunnel --url http://localhost:88 2>cf.log 1>/dev/null &
while True:
  with open('cf.log', 'r') as f:
    for l in f:
      if ".trycloudflare.com" in l:
        print('WebUI URL: ',l[l.find("http"):-2].strip())
        break
    else:
      import time; time.sleep(0.5)
      continue
    break

!udocker --allow-root run -p 88:8188 --hostenv -v /usr -v /etc --entrypoint=sh ubuntu -c 'cd ~/ComfyUI; python main.py --preview-method auto'
# CPU 运行在 python main.py 启动参数里加上 --cpu

如何做到的?
旧版使用的是 ComfyUI-Manager 里的安装脚本,它默认创建一个隔离的 python 环境,这需要重新安装所有依赖。
由于 Colab 本身已经安装了大部分库,我们可以直接利用起来。Colab 还对 Cuda 相关包做了缓存,所以不指定版本可以省去不少下载时间,同时也节省了空间。现在,udocker 只负责隐匿程序目录,环境均在宿主处理。
此外,还稍微完善了一下 WebUI 入口展示方式,不再需要手动打开文件查看了。

以下是旧的通用脚本

之前写了个 Stable Diffusion 版本的,这次是 ComfyUI 版本。

以下是 CPU 版本,GPU 只要把注释的两行打开即可。

启动大约需要 7 分钟,空框架不含模型。web 入口在 access.txt 中,可以通过侧边管理查看。

!wget -q -c 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64' -O cfd
!chmod a+x cfd

!pip install udocker
!udocker --allow-root pull ubuntu:latest
!udocker --allow-root create --name=ubuntu ubuntu:latest
# !udocker --allow-root setup --nvidia ubuntu
!udocker --allow-root run --entrypoint=sh ubuntu -c 'apt update; apt install -y git python-is-python3 python3.10-venv python3-pip wget'
!udocker --allow-root run --entrypoint=sh ubuntu -c 'wget -O - https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/scripts/install-comfyui-venv-linux.sh | bash'
!udocker --allow-root run --entrypoint=sh ubuntu -c 'pip cache purge'

!nohup ./cfd tunnel --url http://localhost:8433 > access.txt &
# !udocker --allow-root run -p 8433:8188 --entrypoint=sh ubuntu -c './run_gpu.sh'
!udocker --allow-root run -p 8433:8188 --entrypoint=sh ubuntu -c './run_cpu.sh'

这里面有不少的坑,有一些还莫名其妙,这里稍微记录一下。

  1. 尽量不用别人现成 docker image,因为结构可能奇奇怪怪。如果深入到容器内修改文件,可能连基本命令都找不到。之前就遇到过用 ChromiumOS 做容器的,wget 难以安装(最后利用 python wget module 替代)。
  2. Colab 对画画的检测还是挺多的,直接安装必然会被掐。如果通过 apt 安装 cloudflared 并通过 thread 调用也会被掐,不知道是哪个环节影响的。
  3. cloudflared 使用自定义域名会导致 ComfyUI-Manager 有几个 js 502 错误无法加载,使用快速随机域名 tunnel 就不会。查了下可能和 tls verify 设置有关,但现在 Cloudflare 后台砍掉了这个设置,暂时不知道去哪改。

10行代码,让colab给我画画

众所周知,colab 已经屏蔽了 stable diffusion,既有文本的粗暴过滤,也有运行时特征检测。就算没有限制,要跑通也不是很轻松的事,而且随时可能因为版本依赖问题歇菜。

这里演示一种简便的绕过方法——使用 docker。

直接上代码,其实都不到 10 行:

!wget -q -c https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -O /tmp/c
!chmod a+x /tmp/c

!pip install udocker
!udocker --allow-root pull universonic/stable-dif${q}fusion-webui:latest
!udocker --allow-root create --name=sdw universonic/stable-dif${q}fusion-webui:latest
!udocker --allow-root setup --nvidia sdw
!udocker --allow-root run --entrypoint=sh sdw -c 'pip cache purge'
!/tmp/c tunnel --url http://localhost:88 &\
 udocker --allow-root run -p 88:7860 --entrypoint=sh sdw -c '~/stable-dif${q}fusion-webui/webui.sh -f'

代码解释:

  1. 首先下载 cloudflared 用于最后建立隧道,因为镜像默认 --share 启动会造成环境崩溃。
  2. 接着是 udocker 替代 docker。由于环境限制,docker 无法在 colab/kaggle 中启动。
  3. q 没有赋值,所以 ${q} 会被系统忽略,这里是用来绕过关键字检测。
  4. webui.sh -f 是允许 root 身份启动。
  5. 以上代码分为两个 cell。启动 webui 会 pip 安装许多模块,为了清理缓存,可以在完全启动后停止再重启第二个 cell(约省 2G 多)。
  6. 因为是在容器内运行,所以外部应该可以删掉很多东西,给模型腾空间,具体哪些可以删晚些时候再研究。

不推荐使用 kaggle 的理由:

  1. stable diffusion webui 不支持多显卡,用 kaggle 纯属浪费。
  2. kaggle 会封杀 NSFW 图片,可能会实时炸号。
  3. kaggle 磁盘上限是以写入量计算,不方便删除切换模型。

WordPress不要搭配sqlite使用

最近 wordpress 自动升级到 6.5,然后后台就登录不了了。页面提示,需要数据库支持 MySQL≥5.5.5。

我并没有使用 MySQL,而是使用 sqlite。显然,开发者根本没考虑这种情况。尝试了一下直接修改数据库和源码,没能绕过检测。于是我通过覆盖降级了 wordpress,然后备份了一下数据重装。

中途换 sqlite 是因为机器磁盘有点小,而 MySQL 本身又挺大的。现在万不得已只好换回来。
教训就是,不要用原生不支持的特性,不知道什么时候就会遇到灾难。

我本地使用的 Windows 版只有 100M,而 linux 上居然有 1G。考虑到磁盘还是捉襟见肘,我打算研究下 MySQL 目录。
简而言之,我删除了 mysql-test,然后对 bin 目录和 lib 整个 upx --lzma --best *,最后只剩 101MB。
之后,我又删除了 nginx/src,再次回收几百 MB,只剩 14MB。

仅通过wget在两台机器间传输文件

发现一个有意思的网站:station307.com

该网站用于两台机器间传输文件,只需要 wget 或 curl 即可。流式传输,而非临时网盘。

接收端输入 wget 命令,在输出中有一行随机生成的 web.url,在浏览器中打开这个地址,选文件发送即可。也可以不经过浏览器直接 post 数据过去。

这有什么好处呢?有时环境比较简单,可能没有 server 或者 ssh 权限,典型的如 kaggle,有了这个网站就可以很方便地发送本地文件。
最近还遇到的一个场景是,目标机器只能 ipv6 访问,正好手上的网络不支持,也用这个网站完成了快速分享。

远程获得APK版本的小脚本

一个很特殊的需求。 有一些上游的 APK 包,这些包都有固定的 url。上游升级 APK 时会覆盖原文件,我需要监控它们的版本号以更新到数据库。 有时候,一些 APK 包会特别大,例如游戏,动辄上 G。所以需要一些办法,不下载整个 APK 来提取信息。

脚本如下:

@echo off

goto :_Preparation
1. Install remotezip:
`pip install remotezip`
2. Download aapt2:
`remotezip https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/8.3.1-10880808/aapt2-8.3.1-10880808-windows.jar aapt2.exe`
:_Preparation

set /p name="APK url: "
remotezip "%name%" AndroidManifest.xml 1>nul
zip -0 AM.zip AndroidManifest.xml 1>nul
aapt2 d badging AM.zip 2>nul|grep package| awk -F "'" "{print $6}{print $4}
del AM.zip AndroidManifest.xml

原理很简单,就是通过 remotezip 提取包内的 AndroidManifest.xml,将其打包进空的 zip,最后通过 aapt 解析。

更新一个Gemini快捷交互方式

之前写了一个在 Colab 上通过 udocker 部署 zhu327/genmini-openai-proxy,最近发现还有更方便的方式。
直接将代理地址改为 https://gemini-openai-proxy.deno.dev 即可接入支持 OpenAI 的客户端。

这是利用了 zuisong/gemini-openai-proxy。上面是公共的,自己搭也很方便。在 deno.dev 新建一个 Playground,直接粘贴进去就部署完毕了,还可以更换二级域名或绑定自己的域名。

和 Colab 相比,好处自然是长期在线。这个项目还有个 CF 版本,不建议使用,因为 CF 会根据地区就近访问,可能会碰到 Google 地区限制。

如果要本地跑,首选还是 zhu327/genmini-openai-proxy。可以编译一个本地版本,UPX 可以压缩到 10M 左右,安全又便携。以下是通过 Colab 编译 Linux / Windows 版本的示例:

%cd /content
!wget -c https://go.dev/dl/go1.21.1.linux-amd64.tar.gz
!tar -xvf go1.21.1.linux-amd64.tar.gz
!chmod +x go/bin/go

!git clone https://github.com/zhu327/gemini-openai-proxy
%cd /content/gemini-openai-proxy
# compile binary for linux
!/content/go/bin/go build -o gemini main.go
# compile binary for windows
!CGO_ENABLED=0 GOOS=windows GOARCH=amd64 /content/go/bin/go build -o gemini.exe main.go

### compress with upx
# !wget https://github.com/upx/upx/releases/download/v4.2.2/upx-4.2.2-amd64_linux.tar.xz
# !tar xvf upx-*
# !chmod a+x upx-4.2.2-amd64_linux/upx
# !upx-4.2.2-amd64_linux/upx --ultra-brute ?? -o??

之所以不用客户端自带的 Gemini 模型,是因为接口默认带有审核,而客户端一般不支持设置相关参数。

尝试做了一个数据集翻译

众所周知,有大语言模型讲话喜欢各种语言混杂,一般是因为融合。
另外,现在有一些公开的未对齐的英文数据集,可以用于对模型本身去审查,但也会造成上述问题。
归根到底,都是因为一开始喂的语料前后文就是混杂的(例如 翻译文章)。

所以我决定对已有的数据集做一些翻译,这样就可以方便其他人直接用中文 de-censored。因为普通数据集有很多,所以我就专注于一些 NSFW 数据。

第一个成果是 unalignment/toxic-dpo-v0.2,一共有 500 多条内容:
中英文对照版:unalignment-toxic-dpo-v0.2-zh_cn

我使用了一个 34B 模型来翻译,小部分来自 Google / DeepL,然后对一些明显有问题的内容做了校对(主要是统一人物称呼、专有名词等)。

全文都是意译的,甚至允许演绎,主要关注是否通顺。
例如,这个数据集中有大量有关迷幻剂和药物的制备内容,我不可能去校对原文或译文是否准确,读起来像是那么回事就行了,目的是用来 Roleplay 或闲聊,而不是真的用于生产环境。其中的故事我通读了一遍,不一定多有文采,但保证能够理解。

其实一开始是想做 NobodyExistsOnTheInternet/ToxicDPOqa,因为有个很喜欢的模型就是用了这个数据集,但是量有点大,我打算先把流程跑通。
最终,500 多条也跑了将近 10 小时才跑完,校对又花了大概 5 小时。原本计划用两个模型各跑一遍,然后让第三个模型来评判哪个通顺,现在看来不太现实。

之后打算看看 athirdpath/DPO_Pairs-Roleplay-Alpaca-NSFW。这个数据集没有分类,我打算只做 sexual content,已经用 mistral 标记好了内容,但打算再找找有没有更好的数据。

【2024.01】目前好用的大语言模型以及部署情况

写于2024年1月。请注意内容是否过时。

之前写了一篇《一些中文LLM的试用体验》,内容有点过时。结合目前的情况更新一下。

依然以家用环境或免费的网络服务为主,也就是说不会出现超过 40B 的模型。
这里要特别提一下 MoE 模型,以 Mixtral-8x7B 为例,这个模型一次只调用 14B,但加载消耗的硬件与 ~40B 的模型相当。MoE 对个人自用来说是不划算的,只适合作为服务部署。

目前好用的中文模型:

这里尤其特指中文模型,因为中文模型比较少,更有不少是浪得虚名。中英文混杂输出是常见病,有些连句子都输出不通顺,这种东西只能自己试了才知道。

NSFW 篇:

非 NSFW 篇

  • DeepSeek 系列,主要是 deepseek-llm-7b-chat,当然 code 模型也很好用。体验 67B 版本可 前往官网。这个模型挺可爱的,有种早期 Sydeny 的感觉。
  • 书生系列的 internlm-chat-20b,这个模型懂很多俚语。也有 7B 版本,但没试过。

不确定的小模型

  • OpenBuddy-Zephyr-7b,印象中是 NSFW 的,能够流畅输出中文。
  • MiniChat-3B,超小的蒸馏模型,玩具,但也可以输出流畅的中文。

※ 部分模型一直在更新版本,具体可以在使用前翻阅作者的模型列表。

当前自用部署量化的情况:

大部分人用的是 text-generation-webui,但我很少用“懒人包”,因为我需要在服务器部署,然后通过兼容 OpenAI API 的接口给本地使用。

目前主流的量化格式包括 GGUF(llama.cpp)、GPTQ、AWQ、exl2(ExllamaV2)。RWKV 另说。
具体推理速度和硬件需求参考这篇 对比文章
总结:exl2 作为 GPTQ 的改良版非常快,GPTQ 和 AWQ 很接近,但 GPTQ 在处理 prompt 阶段明显更快,这对于超长文本比较重要,GGUF 是最慢的。

所以我推荐的是 GGUF。是的,GGUF 是最慢的,但是推荐。

先说 GGUF。家用硬件性能有限,使用模型都是奔着榨干性能上限去,而量化需要更多的资源,大量现成的 GGUF 就很实用。GGUF 还可以混合 CPU 和 GPU 部署,实在没显卡的话,慢总比不能用好。
GGUF 虽然慢,但也没有非常慢,相对 GPTQ 和 AWQ 并没有量级差。只要输出速度没有拖累阅读速度,就不会感觉到卡顿。
最最最重要的是独立二进制文件,不会存在依赖问题。

GGUF 如果部署为 server,有两种方案。

第一种最简单,用 llama.cpp-python,并且有现成的 cuBLAS wheel

# 以colab环境为例
!pip install llama-cpp-python[server] --prefer-binary --extra-index-url=https://jllllll.github.io/llama-cpp-python-cuBLAS-wheels/AVX2/cu118
!python -m llama_cpp.server --model ./model.gguf --n_gpu_layers 1000 --chat_format chatml --host 0.0.0.0 --port 8000

不过这里有个问题,chat_format 是写死在代码里的,要改需要改源代码,自己重新编译。如果模板里正好有对应的格式,那这个最方便。

第二种是直接从 llama.cpp 编译 server。这里我以 Kaggle 环境为例,因为它的 libcuda.so 位置比较刁钻,需要修改一下源码才能编译。

%cd /kaggle
!git clone https://github.com/ggerganov/llama.cpp
%cd /kaggle/llama.cpp
!sed -i 's| -lcuda | -L/usr/local/nvidia/lib64 -lcuda |g' /kaggle/llama.cpp/Makefile
!make -j server LLAMA_CUBLAS=1

编译完成后的二进制文件可以保存下来,下次就可以直接拿来用了。

server 提供的接口不是 OpenAI 格式的,可以启动项目中的 api_like_OAI.py 兼容。这里可以参考 llama-cpp-oai-like-server。我做了一个不太优雅的兼容,重点是很容易定义聊天格式,直接替代原始的 api_like_OAI.py 使用。

然后说 GPTQ 和 AWQ。比较常见的是用 auto-gptq 和 auto-awq 加载。但是这两个模块经常会受到上游包更新的影响,例如 transformer。一旦出现冲突,就需要等作者更新。
如果经常在 Colab 这种环境跑,每次都是新安装,部署就容易出问题。
此外,GPTQ 要求所有模块使用 GPU 版本,不然只能关闭 Exallma,这会很影响推理速度。

如果一定要用的话,推荐 AWQ+fastllm(不要用 vllm,问题实在太多)
Colab 版本大致如下:

!pip install "fschat[model_worker,webui]"
!pip install auto-awq
!python -m fastchat.serve.controller --host 0.0.0.0 &\
python -m fastchat.serve.model_worker --model-path Author/M-AWQ --host 0.0.0.0 &\
python -m fastchat.serve.openai_api_server --host 0.0.0.0 --port 8000

接着说 exl2。很快,但资源很少,量化是最最最耗时的,一个次量化几小时不算长。除非是决定日常要一直用某个模型,或者要部署成在线服务,否则不太推荐。

最后说 RWKV。RWKV 属于比较奇怪的存在,有两种方法在服务器上部署。

第一种是用 cgisky1980/ai00_rwkv_server。比较有意思的是这个项目用的是 webGPU 而不是 CUDA。
Colab 环境的重点是要安装 libnvidia-gl-XXX 这个包。其他跟随项目介绍就行了。
并不太推荐。一是不能多卡部署,二是报错不太友好有问题难定位,三是 KV Cache 有点问题。

第二种是用 josStorer/RWKV-Runner。要分两步执行,大致如下:

# 启动一个后端
import os
os.environ['RWKV_CUDA_ON'] = '1'
!python ./RWKV-Runner/backend-python/main.py --port 8000
# 通过 API 加载模型
curl http://your.site/switch-model -X POST -H "Content-Type: application/json"\
-d '{"model":"./RWKV-Runner/models/the_model.pth","strategy":"cuda:0 fp16 *20 -> cuda:1 fp16"}'

加载策略(strategy)参考 这个指南。怎么量化就只能怎么加载,想要改只能重新量化。
支持多卡,但多卡推理时会遇到一点问题,输出结果有折扣,暂不清楚原因。

结论就是:RWKV 在多卡方面都会遇到挫折。

总结:

当前非常推荐 GGUF,尽管相比其他量化慢一些,但最不容易随升级出问题。而且在线临时环境部署非常轻松,可以直接使用以前生成的 binary,而不需要每次都安装很多依赖。
未来可能会推荐 exl2,视其生态发展而定。